diff --git a/.dockerignore b/.dockerignore index 7f15c4204..9269854cc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,4 +6,5 @@ README.md .next .git dev -.build \ No newline at end of file +.build +e2e \ No newline at end of file diff --git a/.env.example b/.env.example index b05d685b1..75f6c3486 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,14 @@ # This file will be committed to version control, so make sure not to have any secrets in it. # If you are cloning this repo, create a copy of this file named `.env` and populate it with your secrets. +# The below secret is not used anywhere but required for Auth.js (Would encrypt JWTs and Mail hashes, both not used) +AUTH_SECRET="supersecret" + +# The below secret is used to encrypt integration secrets in the database. +# It should be a 32-byte string, generated by running `openssl rand -hex 32` on Unix +# or starting the project without any (which will show a randomly generated one). +SECRET_ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000 + # This is how you can use the sqlite driver: DB_DRIVER='better-sqlite3' DB_URL='FULL_PATH_TO_YOUR_SQLITE_DB_FILE' @@ -20,10 +28,9 @@ DB_URL='FULL_PATH_TO_YOUR_SQLITE_DB_FILE' # DB_PASSWORD='password' # DB_NAME='name-of-database' - -# You can generate the secret via 'openssl rand -base64 32' on Unix -# @see https://next-auth.js.org/configuration/options#secret -AUTH_SECRET='supersecret' +# The below path can be used to store trusted certificates during development, it is not required and can be left empty. +# If it is used, please use the full path to the directory where the certificates are stored. +# LOCAL_CERTIFICATE_PATH='FULL_PATH_TO_CERTIFICATES' TURBO_TELEMETRY_DISABLED=1 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 54199a8d4..e03d0202b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,37 +1,78 @@ name: 🐞 Bug Report -description: Create a bug report to help us improve +description: Report that something is broken, not working as intended or causes side-effects title: "bug: " -labels: ["🐞❔ unconfirmed bug"] +labels: ["needs triage"] body: - - type: textarea - attributes: - label: Provide environment information - description: | - Run this command in your project root and paste the results in a code block: - ```bash - npx envinfo --system --binaries - ``` - validations: - required: true - type: textarea attributes: label: Describe the bug description: A clear and concise description of the bug, as well as what you expected to happen when encountering it. validations: required: true - - type: input + - type: textarea attributes: - label: Link to reproduction - description: Please provide a link to a reproduction of the bug. Issues without a reproduction repo may be ignored. + label: Steps to reproduce + description: Describe how to reproduce your bug. Steps, code snippets, reproduction repos etc. validations: required: true - type: textarea attributes: - label: To reproduce - description: Describe how to reproduce your bug. Steps, code snippets, reproduction repos etc. + label: Impact + description: How big is the impact of this bug? Does it make Homarr unusable? Is there any workaround that you're aware of? validations: required: true - type: textarea attributes: label: Additional information description: Add any other information related to the bug here, screenshots if applicable. + - type: dropdown + id: version + attributes: + label: Version + description: What version of Homarr are you running? + options: + - 1.0.0-beta + - Other (describe in "additional information") + default: 0 + validations: + required: true + - type: dropdown + id: installationMethod + attributes: + label: Installation method + description: How do you run Homarr? Post docker-compose, configs or screenshots if applicable. + options: + - Docker Run + - Docker Compose + - Portainer + - Helm + - QNAP + - Saltbox + - EasyPanel + - Unraid Apps + - TrueNAS Apps + - Synology + - HomeAssistant Addon + - From Source + - Other (describe in "additional information") + default: 0 + validations: + required: true + - type: dropdown + id: browser + attributes: + label: Browser + description: If relevant, what browser do you use? + options: + - Firefox + - Edge (Chromium) + - Edge (Proprietary) + - Chrome + - Safari + - Vivaldi + - Brave + - Samsung Internet + - Other (describe in "additional information") + default: 0 + validations: + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index c2be403e0..a2f69cc3a 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -2,26 +2,16 @@ # See here: https://github.com/vercel/next.js/blob/canary/.github/ISSUE_TEMPLATE/3.feature_request.yml name: 🛠 Feature Request -description: Create a feature request for the core packages +description: Request a new feature that you would like to have implemented title: "feat: " -labels: ["✨ enhancement"] +labels: ["needs triage"] body: - - type: markdown - attributes: - value: | - Thank you for taking the time to file a feature request. Please fill out this form as completely as possible. - type: textarea attributes: label: Describe the feature you'd like to request description: Please describe the feature as clear and concise as possible. Remember to add context as to why you believe this feature is needed. validations: required: true - - type: textarea - attributes: - label: Describe the solution you'd like to see - description: Please describe the solution you would like to see. Adding example usage is a good way to provide context. - validations: - required: true - type: textarea attributes: label: Additional information diff --git a/.github/ISSUE_TEMPLATE/integration.yml b/.github/ISSUE_TEMPLATE/integration.yml new file mode 100644 index 000000000..3aeb492e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/integration.yml @@ -0,0 +1,40 @@ +name: 🛠 Integration request +description: Request support for a new integration (eg. Sonarr, Radarr) +title: "feat: " +labels: ["needs triage"] +body: + - type: input + attributes: + label: Project Website + description: Post the link to the website of the application. Paste the official link. + placeholder: ex. https://sonarr.tv/ + validations: + required: true + - type: textarea + attributes: + label: Describe what data should be consumed by Homarr + description: Please describe what data Homarr should fetch from the integration. Specify in what interval data should be fetched and whether the user can also perform write operations (eg. deleting a movie or adding a user). + validations: + required: true + - type: textarea + attributes: + label: Additional information + description: Add any other information related to the integration. + - type: dropdown + attributes: + label: Public API available? + description: Is there a public API available, that we can consume in Homarr? + options: + - Yes, available on a website + - Yes, available in the application itself + - No + validations: + required: true + - type: dropdown + attributes: + label: Are you willing to contribute this yourself? + options: + - Yes + - No + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/widget.yml b/.github/ISSUE_TEMPLATE/widget.yml new file mode 100644 index 000000000..9ede8d0ba --- /dev/null +++ b/.github/ISSUE_TEMPLATE/widget.yml @@ -0,0 +1,30 @@ +name: 🛠 Widget request +description: Request a new widget (eg. Clock, Calendar, ...) +title: "feat: " +labels: ["needs triage"] +body: + - type: input + attributes: + label: Compatible integrations + description: Post a list of the integrations that should be compatible with this widget. Divide using comma. Leave empty if no integration is needed. + placeholder: ex. Sonarr, Radarr, Lidarr, Readarr, Nextcloud + validations: + required: false + - type: textarea + attributes: + label: Describe what data should be displayed + description: Please describe what data Homarr should display. Describe how elements should be intractable and what actions the user can perform. + validations: + required: true + - type: textarea + attributes: + label: Additional information + description: Add any other information related to the widget. + - type: dropdown + attributes: + label: Are you willing to contribute this yourself? + options: + - Yes + - No + validations: + required: true diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 377002605..a76fd60c1 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -6,6 +6,11 @@ matchPackagePatterns: ["^@homarr/"], enabled: false, }, + // Disable Dockerode updates see https://github.com/apocas/dockerode/issues/787 + { + matchPackagePatterns: ["^dockerode$"], + enabled: false, + }, { matchUpdateTypes: ["minor", "patch", "pin", "digest"], automerge: true, diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index a93cfe2f2..92efa0d03 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -91,6 +91,8 @@ jobs: network: host env: SKIP_ENV_VALIDATION: true + - name: Install playwright browsers + run: pnpm exec playwright install chromium - name: Run E2E Tests shell: bash run: pnpm test:e2e diff --git a/.github/workflows/crowdin-schedule-download.yml b/.github/workflows/crowdin-schedule-download.yml index 15c9aad2e..2891536a4 100644 --- a/.github/workflows/crowdin-schedule-download.yml +++ b/.github/workflows/crowdin-schedule-download.yml @@ -42,7 +42,8 @@ jobs: CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - name: Enable auto-merge + if: steps.crowdin-download.outputs.pull_request_number != '' && steps.crowdin-download.outputs.pull_request_number != null env: GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }} run: | - gh pr merge ${{steps.crowdin-download.pull_request_number}} --auto --merge --squash --delete-branch --title "chore(lang): updated translations from crowdin" + gh pr merge ${{steps.crowdin-download.outputs.pull_request_number}} --auto --squash --delete-branch --subject "chore(lang): updated translations from crowdin" diff --git a/.github/workflows/deployment-docker-image.yml b/.github/workflows/deployment-docker-image.yml index f00513efd..ab7ef7e1b 100644 --- a/.github/workflows/deployment-docker-image.yml +++ b/.github/workflows/deployment-docker-image.yml @@ -4,6 +4,8 @@ on: push: branches: - main + - beta + - dev workflow_dispatch: inputs: send-notifications: @@ -11,11 +13,6 @@ on: required: false default: true description: Send notifications - push-image: - type: boolean - required: false - default: true - description: Push Docker Image permissions: contents: write @@ -27,34 +24,102 @@ env: IMAGE_NAME: ${{ github.repository }} TURBO_TELEMETRY_DISABLED: 1 -concurrency: production +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }} jobs: + release: + name: Create tag and release + runs-on: ubuntu-latest + env: + SKIP_RELEASE: ${{ github.event_name == 'workflow_dispatch' || github.ref_name == 'dev' }} + outputs: + version: ${{ steps.read-semver.outputs.version || steps.version-fallback.outputs.version }} + git_ref: ${{ steps.read-git-ref.outputs.ref || github.ref }} + + steps: + - run: echo "Skipping release for workflow_dispatch event" + if: env.SKIP_RELEASE == 'true' + # The below generated version fallback represents a normalized branch name, for example "feature/branch-name" -> "feature-branch-name" + - run: echo "version="$(echo ${{github.ref_name}} | sed 's/[^a-zA-Z0-9\-]/-/g') >> "$GITHUB_OUTPUT" + id: version-fallback + if: env.SKIP_RELEASE == 'true' && github.ref_name != 'main' && github.ref_name != 'beta' + + - name: Obtain token + if: env.SKIP_RELEASE == 'false' + id: obtainToken + uses: tibdex/github-app-token@v2 + with: + private_key: ${{ secrets.RENOVATE_MERGE_PRIVATE_KEY }} + app_id: ${{ secrets.RENOVATE_MERGE_APP_ID }} + - uses: actions/checkout@v4 + if: env.SKIP_RELEASE == 'false' + with: + persist-credentials: false + - uses: actions/setup-node@v4 + if: env.SKIP_RELEASE == 'false' + with: + node-version: 22 + - run: npm i -g pnpm + if: env.SKIP_RELEASE == 'false' + - name: Install dependencies + if: env.SKIP_RELEASE == 'false' + run: | + pnpm install + - name: Run Semantic Release + if: env.SKIP_RELEASE == 'false' + env: + GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }} + GIT_AUTHOR_NAME: "Releases Homarr" + GIT_AUTHOR_EMAIL: "175486441+homarr-releases[bot]@users.noreply.github.com" + GIT_COMMITTER_NAME: "Releases Homarr" + GIT_COMMITTER_EMAIL: "175486441+homarr-releases[bot]@users.noreply.github.com" + run: | + pnpm release + - name: Read semver output + # We read the last tag either from the created release or from the current branch, this is to rerun the deployment job for the currently released version when it failed + if: env.SKIP_RELEASE == 'false' || github.ref_name == 'main' || github.ref_name == 'beta' + id: read-semver + run: | + git fetch --tags + echo "version=$(git describe --tags --abbrev=0)" >> "$GITHUB_OUTPUT" + - name: Read git ref + if: env.SKIP_RELEASE == 'false' + id: read-git-ref + run: | + echo "ref=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + - name: Update dev branch + if: env.SKIP_RELEASE == 'false' + continue-on-error: true # Prevent pipeline from failing when merge fails + env: + GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }} + run: | + git config user.name "Releases Homarr" + git config user.email "175486441+homarr-releases[bot]@users.noreply.github.com" + git fetch origin dev + git checkout dev + git pull origin dev + git merge ${{ github.ref_name }} + git push origin dev deploy: name: Deploy docker image + needs: release runs-on: ubuntu-latest + env: + NEXT_VERSION: ${{ needs.release.outputs.version }} + DEPLOY_LATEST: ${{ github.ref_name == 'main' }} + DEPLOY_BETA: ${{ github.ref_name == 'beta' }} steps: - - name: Discord notification - if: ${{ github.events.inputs.send-notifications != false }} - env: - DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} - uses: Ilshidur/action-discord@master - with: - args: "Deployment of an image has been triggered: [run ${{ github.run_number }}](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>)" - uses: actions/checkout@v4 - - name: Get Next Version - id: semver - uses: ietf-tools/semver-action@v1 with: - token: ${{ github.token }} - branch: dev + ref: ${{ needs.release.outputs.git_ref }} - name: Discord notification if: ${{ github.events.inputs.send-notifications != false }} env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} uses: Ilshidur/action-discord@master with: - args: "Semver computed next tag to be ${{ steps.semver.outputs.next }}. Current is ${{ steps.semver.outputs.current }}. Building images..." + args: "Deployment of an image for version '${{env.NEXT_VERSION}}' has been triggered: [run ${{ github.run_number }}](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>)" - name: Log in to the Container registry uses: docker/login-action@v3 with: @@ -71,15 +136,12 @@ jobs: with: images: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" tags: | - type=raw,value=alpha - type=raw,value=early-adopters - # tags: | - # type=raw,value=latest - # type=raw,value=${{ steps.semver.outputs.next }} + ${{ env.DEPLOY_LATEST == 'true' && 'type=raw,value=latest' || null }} + ${{ env.DEPLOY_BETA == 'true' && 'type=raw,value=beta' || null }} + type=raw,value=${{ env.NEXT_VERSION }} - name: Build and push id: buildPushAction uses: docker/build-push-action@v6 - if: ${{ github.events.inputs.push-image == 'true' || github.events.inputs.push-image == null }} with: platforms: linux/amd64,linux/arm64 context: . @@ -89,30 +151,9 @@ jobs: network: host env: SKIP_ENV_VALIDATION: true - - name: Build - id: buildPushDryAction - uses: docker/build-push-action@v6 - if: ${{ github.events.inputs.push-image == 'false' }} - with: - platforms: linux/amd64,linux/arm64 - context: . - push: false - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - network: host - env: - SKIP_ENV_VALIDATION: true - name: Discord notification - if: ${{ github.events.inputs.send-notifications != false && (github.events.inputs.push-image == 'true' || github.events.inputs.push-image == null) }} env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} uses: Ilshidur/action-discord@master with: - args: "Deployment of image has completed. Image ID is '${{ steps.buildPushAction.outputs.imageid }}'." - - name: Discord notification - if: ${{ github.events.inputs.send-notifications != false && !(github.events.inputs.push-image == 'true' || github.events.inputs.push-image == null) }} - env: - DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} - uses: Ilshidur/action-discord@master - with: - args: "Deployment of image has completed. Image ID is '${{ steps.buildPushDryAction.outputs.imageid }}'. This was a dry run." + args: "Deployment of image has completed for branch ${{ github.ref_name }}. Image ID is '${{ steps.buildPushAction.outputs.imageid }}'." diff --git a/.github/workflows/deployment-weekly-release.yml b/.github/workflows/deployment-weekly-release.yml index 9177db3cd..dc5fa0a2e 100644 --- a/.github/workflows/deployment-weekly-release.yml +++ b/.github/workflows/deployment-weekly-release.yml @@ -37,7 +37,7 @@ jobs: token: ${{ github.token }} branch: dev - name: Create pull request - run: "gh pr create --title \"chore(release): automatic release ${{ steps.semver.outputs.next }}\" --body \"**This is an automatic release**.
Manual action may be required for major bumps.
Detected change to be ``${{ steps.semver.outputs.bump }}``
Bump version from ``${{ steps.semver.outputs.current }}`` to ``${{ steps.semver.outputs.next }}``\" --base main --head dev --label automerge" + run: 'gh pr create --title "chore(release): automatic release ${{ steps.semver.outputs.next }}" --body "**This is an automatic release**.
Manual action may be required for major bumps.
Detected change to be ``${{ steps.semver.outputs.bump }}``
Bump version from ``${{ steps.semver.outputs.current }}`` to ``${{ steps.semver.outputs.next }}``" --base main --head dev --label automerge' env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - name: Discord notification diff --git a/.gitignore b/.gitignore index bdc55c860..76c8f08fc 100644 --- a/.gitignore +++ b/.gitignore @@ -54,10 +54,14 @@ yarn-error.log* *.log apps/tasks/tasks.cjs +apps/tasks/tasks.css apps/websocket/wssServer.cjs +apps/websocket/wssServer.css apps/nextjs/.million/ packages/cli/cli.cjs +# e2e mounts +e2e/shared/tmp #personal backgrounds -apps/nextjs/public/images/background.png \ No newline at end of file +apps/nextjs/public/images/background.png diff --git a/.nvmrc b/.nvmrc index 1d9b7831b..6fa8dec4c 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22.12.0 +22.13.0 diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 000000000..e2414a583 --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,51 @@ +{ + "branches": [ + "main", + { + "name": "beta", + "prerelease": true, + "channel": "beta" + } + ], + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits" + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits" + } + ], + [ + "@semantic-release/changelog", + { + "changelogFile": "CHANGELOG.md" + } + ], + [ + "@semantic-release/npm", + { + "npmPublish": false + } + ], + [ + "@semantic-release/git", + { + "assets": ["package.json", "CHANGELOG.md"], + "message": "chore(release): ${nextRelease.version} [skip ci]" + } + ], + [ + "@semantic-release/github", + { + "successComment": false, + "failComment": false, + "releaseBodyTemplate": "<%= _.truncate(nextRelease.notes, { 'length': 124000, 'omission': '' }) %>" + } + ] + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 2e67df382..51d2500a1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -39,5 +39,5 @@ "i18n-ally.localesPaths": [ "packages/translation/src/lang", ], - "i18n-ally.keystyle": "auto", + "i18n-ally.keystyle": "nested", } diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..159aeda51 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1231 @@ +## [1.0.0-beta.12](https://github.com/homarr-labs/homarr/compare/v1.0.0-beta.11...v1.0.0-beta.12) (2025-01-10) + +### Features + +* **app:** add search and pagination ([#1860](https://github.com/homarr-labs/homarr/issues/1860)) ([ccb19e0](https://github.com/homarr-labs/homarr/commit/ccb19e06c192029a81c851900982d52b045185a6)) +* **auth:** add env variable for oidc-name-attribute-overwrite ([#1850](https://github.com/homarr-labs/homarr/issues/1850)) ([c349bf8](https://github.com/homarr-labs/homarr/commit/c349bf83714739ca1bc6057f2d43c9e3964fa205)) +* **board:** add board duplication ([#1856](https://github.com/homarr-labs/homarr/issues/1856)) ([49d10f7](https://github.com/homarr-labs/homarr/commit/49d10f7ad0f58b577ed72c2a46a062af263ff225)) +* docker add to homarr ([#1825](https://github.com/homarr-labs/homarr/issues/1825)) ([64cc078](https://github.com/homarr-labs/homarr/commit/64cc078b095e64edca17e07a09a4f5c340665f84)) +* **icons:** add upload button to icon picker ([#1859](https://github.com/homarr-labs/homarr/issues/1859)) ([1e9098d](https://github.com/homarr-labs/homarr/commit/1e9098d052801fe7d53ce15e9f22ed89de04d644)) +* **items:** add search to selection ([#1887](https://github.com/homarr-labs/homarr/issues/1887)) ([62da953](https://github.com/homarr-labs/homarr/commit/62da953356ff76694ddc50980a2b879a01bcbdd6)) +* **spotlight:** add default search engine ([#1807](https://github.com/homarr-labs/homarr/issues/1807)) ([65befa2](https://github.com/homarr-labs/homarr/commit/65befa22ba91c36a3734ac6dc027175dc9fca892)) + +### Bug Fixes + +* **deps:** update dependency @tabler/icons-react to ^3.27.1 ([#1875](https://github.com/homarr-labs/homarr/issues/1875)) ([e46b1c4](https://github.com/homarr-labs/homarr/commit/e46b1c49f9bb1320f82b2de0585f7e2c7bc72c54)) +* **deps:** update dependency @tabler/icons-react to ^3.28.1 ([#1891](https://github.com/homarr-labs/homarr/issues/1891)) ([ffdc8d3](https://github.com/homarr-labs/homarr/commit/ffdc8d34960dea0172c50a1d93a4cd14997b13ac)) +* **deps:** update dependency better-sqlite3 to ^11.7.2 ([#1858](https://github.com/homarr-labs/homarr/issues/1858)) ([1f0116d](https://github.com/homarr-labs/homarr/commit/1f0116d725d76845df4b9cce74ef87134edc627a)) +* **deps:** update dependency dockerode to ^4.0.3 ([#1854](https://github.com/homarr-labs/homarr/issues/1854)) ([92f4f94](https://github.com/homarr-labs/homarr/commit/92f4f9421e8f693e6546716f5f04922161e29cdc)) +* **deps:** update dependency glob to ^11.0.1 ([#1908](https://github.com/homarr-labs/homarr/issues/1908)) ([7d1b1d8](https://github.com/homarr-labs/homarr/commit/7d1b1d83429acaa9846479a7a5c48092d4614b75)) +* **deps:** update dependency ldapts to v7.3.1 ([#1896](https://github.com/homarr-labs/homarr/issues/1896)) ([a69c64d](https://github.com/homarr-labs/homarr/commit/a69c64d88d57293eba8adbdf88ce694194268492)) +* **deps:** update dependency mantine-react-table to v2.0.0-beta.8 ([#1902](https://github.com/homarr-labs/homarr/issues/1902)) ([86a9259](https://github.com/homarr-labs/homarr/commit/86a925939cb8ef92fe0bca5a762e688887916b04)) +* **deps:** update dependency octokit to ^4.1.0 ([#1898](https://github.com/homarr-labs/homarr/issues/1898)) ([3860af3](https://github.com/homarr-labs/homarr/commit/3860af31b64e8a74e7e1c91470a9de5450f9e5e7)) +* **deps:** update dependency sass to ^1.83.1 ([#1852](https://github.com/homarr-labs/homarr/issues/1852)) ([812469d](https://github.com/homarr-labs/homarr/commit/812469db827badee63c73a8c819922c24fdefd13)) +* **deps:** update dependency trpc-to-openapi to ^2.1.2 ([#1900](https://github.com/homarr-labs/homarr/issues/1900)) ([8edf922](https://github.com/homarr-labs/homarr/commit/8edf922e3050ba9d8c951180ae68f628067c190e)) +* **deps:** update dependency typescript-eslint to ^8.19.1 ([#1874](https://github.com/homarr-labs/homarr/issues/1874)) ([be4e753](https://github.com/homarr-labs/homarr/commit/be4e75321a0a6a05c6ac6c4ba97ffb5068aed4aa)) +* **deps:** update dependency undici to v7.2.1 ([#1904](https://github.com/homarr-labs/homarr/issues/1904)) ([b034dcb](https://github.com/homarr-labs/homarr/commit/b034dcbb11017a016e30db0e2bf8c1a0765174ca)) +* **deps:** update mantine monorepo to ^7.15.3 ([#1880](https://github.com/homarr-labs/homarr/issues/1880)) ([7807b28](https://github.com/homarr-labs/homarr/commit/7807b28d24327db89514da533cb06f4c296b579d)) +* **deps:** update nextjs monorepo to ^15.1.4 ([#1885](https://github.com/homarr-labs/homarr/issues/1885)) ([f4f02ca](https://github.com/homarr-labs/homarr/commit/f4f02ca539609705b7192c4327272f88415e1594)) +* **deps:** update nextjs monorepo to v15 (major) ([#1844](https://github.com/homarr-labs/homarr/issues/1844)) ([d985525](https://github.com/homarr-labs/homarr/commit/d98552540a9eb3c24ba92a490f921c2b1911b1f6)) +* **deps:** update tanstack-query monorepo to ^5.62.14 ([#1846](https://github.com/homarr-labs/homarr/issues/1846)) ([2358f6f](https://github.com/homarr-labs/homarr/commit/2358f6f5ebf4bbb9eb4ccd91990f967d9cc44e3b)) +* **deps:** update tanstack-query monorepo to ^5.62.15 ([#1853](https://github.com/homarr-labs/homarr/issues/1853)) ([53f07f8](https://github.com/homarr-labs/homarr/commit/53f07f87b8d600ce57fa94d2ffb4d6f0105102d0)) +* **deps:** update tanstack-query monorepo to ^5.62.16 ([#1877](https://github.com/homarr-labs/homarr/issues/1877)) ([eb424d7](https://github.com/homarr-labs/homarr/commit/eb424d757b7934d5a6bce9de943528f17e678b80)) +* **deps:** update tanstack-query monorepo to ^5.63.0 ([#1893](https://github.com/homarr-labs/homarr/issues/1893)) ([e33e0a4](https://github.com/homarr-labs/homarr/commit/e33e0a4d2bd91d610c6d29522a98cae8b9953478)) +* **deps:** update tiptap monorepo to v2.11.1 ([#1909](https://github.com/homarr-labs/homarr/issues/1909)) ([dc3d27e](https://github.com/homarr-labs/homarr/commit/dc3d27e1a1b1611c1997235bf51daf00e3d1f239)) +* **deps:** update tiptap monorepo to v2.11.2 ([#1913](https://github.com/homarr-labs/homarr/issues/1913)) ([9a7e421](https://github.com/homarr-labs/homarr/commit/9a7e421f6827a5a0ac3627318e51537840295e72)) +* **dns-hole-summary:** calculation for domains and percentage for multiple integrations ([#1894](https://github.com/homarr-labs/homarr/issues/1894)) ([546c824](https://github.com/homarr-labs/homarr/commit/546c824888a2a6909b831b69ce1a4e283099bda5)) +* **iframe:** remove second scrollbar from item card ([#1828](https://github.com/homarr-labs/homarr/issues/1828)) ([bf12944](https://github.com/homarr-labs/homarr/commit/bf1294476867fabc896f94c9326a1acfe6bffa50)) +* **security:** restrict link protocols to http and https ([#1888](https://github.com/homarr-labs/homarr/issues/1888)) ([a12dd10](https://github.com/homarr-labs/homarr/commit/a12dd102692ee237e9695bd852dc894a2856b30e)) +* **translation:** query parameter in search with escaped ([#1895](https://github.com/homarr-labs/homarr/issues/1895)) ([80c02ef](https://github.com/homarr-labs/homarr/commit/80c02ef9f24cec74025a0fcc983c6db37f7fd457)) +* **widget:** set-options from widget components should be partial ([#1882](https://github.com/homarr-labs/homarr/issues/1882)) ([e695fb6](https://github.com/homarr-labs/homarr/commit/e695fb64d317ecb47b6844dc2a185502244f7db1)) + +## [1.0.0-beta.11](https://github.com/homarr-labs/homarr/compare/v1.0.0-beta.10...v1.0.0-beta.11) (2025-01-03) + +### Features + +* remove import beta badge ([#1829](https://github.com/homarr-labs/homarr/issues/1829)) ([6305c74](https://github.com/homarr-labs/homarr/commit/6305c74f90d943722c915ffbf54b5fd7e68a7dca)) + +### Bug Fixes + +* **deps:** update dependency zod-form-data to ^2.0.5 ([#1822](https://github.com/homarr-labs/homarr/issues/1822)) ([a234fc8](https://github.com/homarr-labs/homarr/commit/a234fc844e5edcef9935efb0725b6ccceadfe69d)) +* **deps:** update tanstack-query monorepo to ^5.62.12 ([#1843](https://github.com/homarr-labs/homarr/issues/1843)) ([bc5e25e](https://github.com/homarr-labs/homarr/commit/bc5e25e9cd3269a3d8cc8ef521ae75aff50088be)) +* **icons:** picker does not allow multiple words ([#1827](https://github.com/homarr-labs/homarr/issues/1827)) ([6e21863](https://github.com/homarr-labs/homarr/commit/6e21863d04f7d0598e7e7ca3fb707f9beb09d7ef)) +* login page in light mode is always black ([#1821](https://github.com/homarr-labs/homarr/issues/1821)) ([cc7d53e](https://github.com/homarr-labs/homarr/commit/cc7d53e84ec8c2dd3698a178ca6f35099194b5d7)) +* prowlarr integration indexers status changed from id to indexerId ([#1837](https://github.com/homarr-labs/homarr/issues/1837)) ([ee8831a](https://github.com/homarr-labs/homarr/commit/ee8831affe34a33b80a0993aa538c2b16c035f11)) + +## [1.0.0-beta.10](https://github.com/homarr-labs/homarr/compare/v1.0.0-beta.9...v1.0.0-beta.10) (2024-12-31) + +### Features + +* add request media ([#1811](https://github.com/homarr-labs/homarr/issues/1811)) ([91e1cef](https://github.com/homarr-labs/homarr/commit/91e1cef611a47d57b42c91c0c6d49fcf2e6a10bb)) +* **docker:** add support for pgid and puid env variables ([#1759](https://github.com/homarr-labs/homarr/issues/1759)) ([aeb681a](https://github.com/homarr-labs/homarr/commit/aeb681a85839e31284e8f1566adc4191a68ea385)) +* **integration:** add search engine creation ([#1816](https://github.com/homarr-labs/homarr/issues/1816)) ([f507645](https://github.com/homarr-labs/homarr/commit/f5076454cd644a99439b697f24bb0b1f871b2205)) +* **widget:** add minecraft server status widget ([#1801](https://github.com/homarr-labs/homarr/issues/1801)) ([0ebf4bc](https://github.com/homarr-labs/homarr/commit/0ebf4bc55e62caf5917340496abb350d564df255)) + +### Bug Fixes + +* **deps:** update dependency octokit to ^4.0.3 ([#1806](https://github.com/homarr-labs/homarr/issues/1806)) ([75aefcb](https://github.com/homarr-labs/homarr/commit/75aefcb0d5210a53e8a00b675dbbce847aa8add4)) +* **deps:** update dependency trpc-to-openapi to ^2.1.1 ([#1788](https://github.com/homarr-labs/homarr/issues/1788)) ([4943e7b](https://github.com/homarr-labs/homarr/commit/4943e7b851cd29291b5e8f2f9d0e084b4deeffc0)) +* **deps:** update dependency typescript-eslint to ^8.19.0 ([#1814](https://github.com/homarr-labs/homarr/issues/1814)) ([598f004](https://github.com/homarr-labs/homarr/commit/598f0047eb13d6d0d6b68c9032a7a6648f4b6aa3)) +* **deps:** update tiptap monorepo to v2.11.0 ([#1813](https://github.com/homarr-labs/homarr/issues/1813)) ([eacda4c](https://github.com/homarr-labs/homarr/commit/eacda4c397cb384a35e9eec0305f9b26f2a22a4a)) +* **docker:** replace anonymous docker volume with env variable for encrypting secrets ([#1809](https://github.com/homarr-labs/homarr/issues/1809)) ([56b57ad](https://github.com/homarr-labs/homarr/commit/56b57ad171da170c2d8edd6112092cef0b586852)) +* **health-monitoring:** add months to uptime, fix status update ([#1792](https://github.com/homarr-labs/homarr/issues/1792)) ([c91aae5](https://github.com/homarr-labs/homarr/commit/c91aae53acf27eab96a9150281f98a2156e9e2af)) +* **media-server:** redesign widget ([#1775](https://github.com/homarr-labs/homarr/issues/1775)) ([23c7d0b](https://github.com/homarr-labs/homarr/commit/23c7d0bbf01215b680f346e7eef8072d8b9db09e)) + +## [1.0.0-beta.9](https://github.com/homarr-labs/homarr/compare/v1.0.0-beta.8...v1.0.0-beta.9) (2024-12-27) + +### Bug Fixes + +* **deps:** update nextjs monorepo to ^14.2.22 ([#1787](https://github.com/homarr-labs/homarr/issues/1787)) ([3d66ff9](https://github.com/homarr-labs/homarr/commit/3d66ff914883a665c0329c8fc4fd087f4d220692)) +* **deps:** update tanstack-query monorepo to ^5.62.11 ([#1791](https://github.com/homarr-labs/homarr/issues/1791)) ([e9870e7](https://github.com/homarr-labs/homarr/commit/e9870e7ee78227d3be773d9d93aa732760cc8e21)) + +## [1.0.0-beta.8](https://github.com/homarr-labs/homarr/compare/v1.0.0-beta.7...v1.0.0-beta.8) (2024-12-25) + +### Bug Fixes + +* **deps:** update dependency @ctrl/deluge to ^7.1.0 ([#1776](https://github.com/homarr-labs/homarr/issues/1776)) ([ecae80d](https://github.com/homarr-labs/homarr/commit/ecae80d741213f12ff08f87992cc4d906cbe0085)) +* **deps:** update dependency @ctrl/transmission to ^7.2.0 ([#1777](https://github.com/homarr-labs/homarr/issues/1777)) ([3e2ffbd](https://github.com/homarr-labs/homarr/commit/3e2ffbd7bf2793ff58136ed75b38e0d96b4a5ca8)) +* **deps:** update dependency drizzle-orm to ^0.38.3 ([#1783](https://github.com/homarr-labs/homarr/issues/1783)) ([82c6ce7](https://github.com/homarr-labs/homarr/commit/82c6ce7b77023881bd4c74fb43437e777f9b219e)) +* **deps:** update dependency drizzle-zod to ^0.6.1 ([#1782](https://github.com/homarr-labs/homarr/issues/1782)) ([555212e](https://github.com/homarr-labs/homarr/commit/555212e2dc82c4b71b8c25a5f20964b3441b5ab9)) +* oldmarr import user casing wrong ([#1784](https://github.com/homarr-labs/homarr/issues/1784)) ([e37279f](https://github.com/homarr-labs/homarr/commit/e37279fe8071773f1a9773e3233bc81cbb336798)) + +## [1.0.0-beta.7](https://github.com/homarr-labs/homarr/compare/v1.0.0-beta.6...v1.0.0-beta.7) (2024-12-24) + +### Features + +* **apps:** remove url variables ([#1771](https://github.com/homarr-labs/homarr/issues/1771)) ([8df398c](https://github.com/homarr-labs/homarr/commit/8df398c3c706369f6990719603a357c161606f81)) + +### Bug Fixes + +* **auth:** oidc redirect does not respect https protocol ([#1763](https://github.com/homarr-labs/homarr/issues/1763)) ([0336803](https://github.com/homarr-labs/homarr/commit/033680355044b1ebfa5d8fe07b59929bbcfcb3a0)) +* **board:** item background and border overridden by mantine card styles ([#1769](https://github.com/homarr-labs/homarr/issues/1769)) ([425359b](https://github.com/homarr-labs/homarr/commit/425359be02f66242f7db0dc77bed0355495e21d5)) +* **board:** tiles order not respected on firefox ([#1770](https://github.com/homarr-labs/homarr/issues/1770)) ([8893b72](https://github.com/homarr-labs/homarr/commit/8893b72fe363691b91b6aca75d4ad37f4b8e9f6a)) +* copy media link ([#1750](https://github.com/homarr-labs/homarr/issues/1750)) ([d78c6ed](https://github.com/homarr-labs/homarr/commit/d78c6ed5299e1f975c2e85ec3ecad38e00457677)) +* **deps:** update dependency @ctrl/qbittorrent to ^9.2.0 ([#1768](https://github.com/homarr-labs/homarr/issues/1768)) ([8b416a6](https://github.com/homarr-labs/homarr/commit/8b416a6dd354b22a3e4f527b793dde2c538b1e6a)) +* **deps:** update dependency eslint-plugin-react to ^7.37.3 ([#1767](https://github.com/homarr-labs/homarr/issues/1767)) ([fe95334](https://github.com/homarr-labs/homarr/commit/fe95334aa70c95faefcf904591fa9d33159b0905)) +* **deps:** update dependency jotai to ^2.11.0 ([#1756](https://github.com/homarr-labs/homarr/issues/1756)) ([4e85bbb](https://github.com/homarr-labs/homarr/commit/4e85bbbad034f08ab84e331d376b7a9c6f54e507)) +* **deps:** update dependency mysql2 to v3.12.0 ([#1758](https://github.com/homarr-labs/homarr/issues/1758)) ([d02ded5](https://github.com/homarr-labs/homarr/commit/d02ded5511aa2d54307db0ac7f4e0a5dee5a707d)) +* **deps:** update dependency react-error-boundary to v5 ([#1748](https://github.com/homarr-labs/homarr/issues/1748)) ([01db27c](https://github.com/homarr-labs/homarr/commit/01db27c34f3daf6e67e35bbd357df31dcb154b41)) +* **deps:** update dependency typescript-eslint to ^8.18.2 ([#1762](https://github.com/homarr-labs/homarr/issues/1762)) ([9223dd0](https://github.com/homarr-labs/homarr/commit/9223dd06ee0c2b51e036f607d7b3252c61ab77ea)) +* **deps:** update mantine monorepo to ^7.15.2 ([#1757](https://github.com/homarr-labs/homarr/issues/1757)) ([dfacb08](https://github.com/homarr-labs/homarr/commit/dfacb08dbddb6864646ece2fca6978207f0c58ac)) +* **deps:** update tanstack-query monorepo to ^5.62.10 ([#1772](https://github.com/homarr-labs/homarr/issues/1772)) ([c410b06](https://github.com/homarr-labs/homarr/commit/c410b06a15ed5426931ad764cc861f66f11a40da)) +* **deps:** update tanstack-query monorepo to ^5.62.9 ([#1761](https://github.com/homarr-labs/homarr/issues/1761)) ([42da2b9](https://github.com/homarr-labs/homarr/commit/42da2b9b062bd8a08c37e45ab129953e8b0e3624)) +* **icons:** local icon repository does not work with medias ([#1765](https://github.com/homarr-labs/homarr/issues/1765)) ([e220087](https://github.com/homarr-labs/homarr/commit/e220087e96c7096303b1d245ccf3941118e692f3)) +* **onboard:** missing admin permission assignment for external group ([#1764](https://github.com/homarr-labs/homarr/issues/1764)) ([b948337](https://github.com/homarr-labs/homarr/commit/b9483379dd56a8dab2b9b636b66b970da4cf9d83)) + +## [1.0.0-beta.6](https://github.com/homarr-labs/homarr/compare/v1.0.0-beta.5...v1.0.0-beta.6) (2024-12-20) + +### Bug Fixes + +* **deps:** update dependency ioredis to v5.4.2 ([#1739](https://github.com/homarr-labs/homarr/issues/1739)) ([720fdb7](https://github.com/homarr-labs/homarr/commit/720fdb772c2142e23b2bfa2ecaddf0063fbe192c)) +* **deps:** update dependency next-intl to v3.26.3 ([#1740](https://github.com/homarr-labs/homarr/issues/1740)) ([fff1da8](https://github.com/homarr-labs/homarr/commit/fff1da88bd44162b08a76f8b2f49e2b929fc56e8)) + +## [1.0.0-beta.5](https://github.com/homarr-labs/homarr/compare/v1.0.0-beta.4...v1.0.0-beta.5) (2024-12-19) + +### Features + +* Add quick filters for integration and status + minor UI improvement from feedback ([#1641](https://github.com/homarr-labs/homarr/issues/1641)) ([b6dad43](https://github.com/homarr-labs/homarr/commit/b6dad438c2f44aa8d7a740c1a22c9d4c39edf43e)) + +### Bug Fixes + +* about version is one behind because of missing package-json update in deploy ([#1725](https://github.com/homarr-labs/homarr/issues/1725)) ([8c11562](https://github.com/homarr-labs/homarr/commit/8c1156240c8a0d332301ae6dd0a4521f3db19d9a)) +* allow additional file-type for oldmarr import ([#1723](https://github.com/homarr-labs/homarr/issues/1723)) ([1e8a535](https://github.com/homarr-labs/homarr/commit/1e8a5359b78e28db7683ba837a962685446c6c32)) +* always require db-user and password for mysql ([#1730](https://github.com/homarr-labs/homarr/issues/1730)) ([d2584b6](https://github.com/homarr-labs/homarr/commit/d2584b63c55ca143a2b5dc6a71cb00fd5612b78a)) +* **deps:** update dependency tldts to ^6.1.69 ([#1726](https://github.com/homarr-labs/homarr/issues/1726)) ([c0f6816](https://github.com/homarr-labs/homarr/commit/c0f681637db1d6e7abdf3326b3a3c17283440d09)) +* **deps:** update dependency undici to v7.2.0 ([#1718](https://github.com/homarr-labs/homarr/issues/1718)) ([61afab5](https://github.com/homarr-labs/homarr/commit/61afab518f6193a700a547faffa4619b28fb0837)) +* **deps:** update dependency zod-form-data to ^2.0.3 ([#1717](https://github.com/homarr-labs/homarr/issues/1717)) ([a7bd664](https://github.com/homarr-labs/homarr/commit/a7bd664c5cee578574bf37b7149a2142be9f8b7a)) +* **deps:** update dependency zod-form-data to ^2.0.4 ([#1719](https://github.com/homarr-labs/homarr/issues/1719)) ([3b7e6cc](https://github.com/homarr-labs/homarr/commit/3b7e6cc083220a0e3a0cf4f5243c073067ba5bc7)) +* **deps:** update nextjs monorepo to ^14.2.21 ([#1727](https://github.com/homarr-labs/homarr/issues/1727)) ([2b4bc83](https://github.com/homarr-labs/homarr/commit/2b4bc8352efa1e2cffb71a6d4d6e42f941358f02)) +* **deps:** update tiptap monorepo to v2.10.4 ([#1729](https://github.com/homarr-labs/homarr/issues/1729)) ([2ae3d93](https://github.com/homarr-labs/homarr/commit/2ae3d938eeea5bd49a74d9c09b4cb2c680b059d0)) +* mysql operations not working ([#1728](https://github.com/homarr-labs/homarr/issues/1728)) ([550bca6](https://github.com/homarr-labs/homarr/commit/550bca6dee743a4ed68ec15677304ecfd7a9a385)) +* update of dev branch has no credentials ([#1724](https://github.com/homarr-labs/homarr/issues/1724)) ([bb7f751](https://github.com/homarr-labs/homarr/commit/bb7f7514814d49a77ac79f63d68923d08148573e)) + +## [1.0.0-beta.4](https://github.com/homarr-labs/homarr/compare/v1.0.0-beta.3...v1.0.0-beta.4) (2024-12-18) + +### Bug Fixes + +* about version reads nextjs package-json ([#1706](https://github.com/homarr-labs/homarr/issues/1706)) ([d803087](https://github.com/homarr-labs/homarr/commit/d8030873452d2248d79d16a2fc4464ff2fbb478d)) +* conflicts between common admin group for ldap or oidc and credentials default group ([#1710](https://github.com/homarr-labs/homarr/issues/1710)) ([3c0f272](https://github.com/homarr-labs/homarr/commit/3c0f272707ee66fd00bffb0d16e30df98b4f1aff)) +* **deps:** update dependency ldapts to v7.3.0 ([#1696](https://github.com/homarr-labs/homarr/issues/1696)) ([6943505](https://github.com/homarr-labs/homarr/commit/694350583a0e53014a950c4a5bed4d487ad4ca7b)) +* **deps:** update dependency next-intl to v3.26.2 ([#1703](https://github.com/homarr-labs/homarr/issues/1703)) ([d3a883a](https://github.com/homarr-labs/homarr/commit/d3a883a252167612f3f64579730c8f26453897e3)) +* docker statup permission issue ([#1709](https://github.com/homarr-labs/homarr/issues/1709)) ([1baa9fc](https://github.com/homarr-labs/homarr/commit/1baa9fc74cf15df8ead7bbe6d1615f7bf0895813)) +* import sidebar issues ([#1712](https://github.com/homarr-labs/homarr/issues/1712)) ([a519994](https://github.com/homarr-labs/homarr/commit/a51999457b57c042b543768bc1ef43647d62a85d)) +* jellyfin integration does not allow username password auth ([#1714](https://github.com/homarr-labs/homarr/issues/1714)) ([63a7be3](https://github.com/homarr-labs/homarr/commit/63a7be35a4cf0f11610c2097afc32d2ced0ef9e1)) +* permission required for home page ([#1711](https://github.com/homarr-labs/homarr/issues/1711)) ([5fbbf03](https://github.com/homarr-labs/homarr/commit/5fbbf037ce8a06642533c7f68c1c34ed8b01e4e4)) + +## [1.0.0-beta.3](https://github.com/homarr-labs/homarr/compare/v1.0.0-beta.2...v1.0.0-beta.3) (2024-12-17) + +### Bug Fixes + +* boolean checks do not work correctly in deploy workflow ([649506b](https://github.com/homarr-labs/homarr/commit/649506b56a5f3cbbee9b782b637730f2196785cc)) + +## [1.0.0-beta.2](https://github.com/homarr-labs/homarr/compare/v1.0.0-beta.1...v1.0.0-beta.2) (2024-12-17) + +### Bug Fixes + +* add missing branch-name to discord deploy notification ([50697eb](https://github.com/homarr-labs/homarr/commit/50697eb21f923bbe9a6811c964cfc313f79a2806)) + +## 1.0.0-beta.1 (2024-12-17) + +### ⚠ BREAKING CHANGES + +* **deps:** update tanstack-query monorepo (#126) + +### Features + +* [#1047](https://github.com/homarr-labs/homarr/issues/1047) add overseerr search ([#1411](https://github.com/homarr-labs/homarr/issues/1411)) ([aa50399](https://github.com/homarr-labs/homarr/commit/aa503992af37bc683f934b36faebd31fba9d8720)) +* [#1243](https://github.com/homarr-labs/homarr/issues/1243) add api routes ([#1286](https://github.com/homarr-labs/homarr/issues/1286)) ([d76b4d0](https://github.com/homarr-labs/homarr/commit/d76b4d0ec185b627eee5e000ca16b78899c950a7)) +* [#1254](https://github.com/homarr-labs/homarr/issues/1254) display group owner ([#1406](https://github.com/homarr-labs/homarr/issues/1406)) ([34506b6](https://github.com/homarr-labs/homarr/commit/34506b6339945d3ee8d6afc84b7f1da8ff9153b0)) +* [#1408](https://github.com/homarr-labs/homarr/issues/1408) add local icon repository ([#1413](https://github.com/homarr-labs/homarr/issues/1413)) ([f31ccf2](https://github.com/homarr-labs/homarr/commit/f31ccf2d6aa9eb0e81e8759527195b7754eb7df3)) +* [#1408](https://github.com/homarr-labs/homarr/issues/1408) improve icon picker design ([#1412](https://github.com/homarr-labs/homarr/issues/1412)) ([441cbbe](https://github.com/homarr-labs/homarr/commit/441cbbe71775e37bf19f44ad2ba4065e839fbfa8)) +* [#420](https://github.com/homarr-labs/homarr/issues/420) reimplement icon picker ([#421](https://github.com/homarr-labs/homarr/issues/421)) ([60a35e2](https://github.com/homarr-labs/homarr/commit/60a35e258363e26df68f96290fd9359f577f1498)) +* [#511](https://github.com/homarr-labs/homarr/issues/511) log user logged in ([#1405](https://github.com/homarr-labs/homarr/issues/1405)) ([b294bf6](https://github.com/homarr-labs/homarr/commit/b294bf68cf4eceaf00ba94fb842f75af05a2c50d)) +* add 404 page ([#145](https://github.com/homarr-labs/homarr/issues/145)) ([60dec6e](https://github.com/homarr-labs/homarr/commit/60dec6e3be68a7f14ffae1f527c671e5d90e7f04)) +* add about page ([#388](https://github.com/homarr-labs/homarr/issues/388)) ([42a5a1a](https://github.com/homarr-labs/homarr/commit/42a5a1a56368cc1dadc61f403bd9a3f696716904)) +* add actual user for trpc wss-dev-server ([#261](https://github.com/homarr-labs/homarr/issues/261)) ([058a8c4](https://github.com/homarr-labs/homarr/commit/058a8c4776d2cd73653f9c40525847576e7b0a2b)), closes [#233](https://github.com/homarr-labs/homarr/issues/233) +* add analytics ([#528](https://github.com/homarr-labs/homarr/issues/528)) ([7e64d39](https://github.com/homarr-labs/homarr/commit/7e64d39693438cc52f37c8aab4fb9b04c851e4b9)) +* add api keys ([#991](https://github.com/homarr-labs/homarr/issues/991)) ([b14f82b](https://github.com/homarr-labs/homarr/commit/b14f82b4bb7be6e68ecaa9db0e1957e39f90823b)) +* add app actions ([#322](https://github.com/homarr-labs/homarr/issues/322)) ([8988880](https://github.com/homarr-labs/homarr/commit/89888804393720c10aab9f03f33d54d039d32a2b)) +* add app widget ([#206](https://github.com/homarr-labs/homarr/issues/206)) ([c4ff968](https://github.com/homarr-labs/homarr/commit/c4ff968cbca9250a8b33b5632e9267ecd0a7863b)) +* Add apps crud ([#174](https://github.com/homarr-labs/homarr/issues/174)) ([8d5984c](https://github.com/homarr-labs/homarr/commit/8d5984c58a6ec6ee04cce49d51ab9aee53577bf9)) +* add async suffix eslint rule ([#485](https://github.com/homarr-labs/homarr/issues/485)) ([dcaff1d](https://github.com/homarr-labs/homarr/commit/dcaff1d91c7789dd1003313e73172b605cd420c5)) +* add board ([#15](https://github.com/homarr-labs/homarr/issues/15)) ([9d52087](https://github.com/homarr-labs/homarr/commit/9d520874f4feb71587d365a82a75e2de93720b4e)) +* add board access settings ([#249](https://github.com/homarr-labs/homarr/issues/249)) ([361700b](https://github.com/homarr-labs/homarr/commit/361700b2394bc616607fdaa25bb7847998f3179f)) +* add boards management page ([#55](https://github.com/homarr-labs/homarr/issues/55)) ([5ef79ed](https://github.com/homarr-labs/homarr/commit/5ef79edc1aac1f675d613255a02741da4d836f81)) +* add bookmark widget ([#964](https://github.com/homarr-labs/homarr/issues/964)) ([49c0ebe](https://github.com/homarr-labs/homarr/commit/49c0ebea6dad6f586fc61073f815a928db4b435b)) +* add calendar widget ([#663](https://github.com/homarr-labs/homarr/issues/663)) ([dba97a3](https://github.com/homarr-labs/homarr/commit/dba97a3bd6d4b29c9079c9ee6ec98aa974614add)) +* add change password form ([#199](https://github.com/homarr-labs/homarr/issues/199)) ([beb7def](https://github.com/homarr-labs/homarr/commit/beb7defd32561ca074b48b4aa72631fdb59ddbdc)) +* add collapse to login screen with cli command for password reset ([#963](https://github.com/homarr-labs/homarr/issues/963)) ([bc886d9](https://github.com/homarr-labs/homarr/commit/bc886d94767cd2898529c0c17ff669bad4a19fad)) +* add colorscheme to user in db ([#987](https://github.com/homarr-labs/homarr/issues/987)) ([b080e0d](https://github.com/homarr-labs/homarr/commit/b080e0de714235756affc4c68854ec6a01269836)) +* add column count and is public options to board creation modal ([#930](https://github.com/homarr-labs/homarr/issues/930)) ([fcb72e6](https://github.com/homarr-labs/homarr/commit/fcb72e67167d3549f4f5b35706cabb0ca155eb8e)) +* add context specific search and actions ([#1570](https://github.com/homarr-labs/homarr/issues/1570)) ([c840ff8](https://github.com/homarr-labs/homarr/commit/c840ff85bcda7b45703e25204c93f1a9531d52dd)) +* add contributors to about page ([#445](https://github.com/homarr-labs/homarr/issues/445)) ([3cda718](https://github.com/homarr-labs/homarr/commit/3cda718474dc5641d4c2c8680ec5369ad5b85cc8)) +* add crawling settings ([#959](https://github.com/homarr-labs/homarr/issues/959)) ([19cd41a](https://github.com/homarr-labs/homarr/commit/19cd41a8e52585963ffe210186daadb1513b4dca)) +* add create board modal ([#131](https://github.com/homarr-labs/homarr/issues/131)) ([e3e38e7](https://github.com/homarr-labs/homarr/commit/e3e38e7f4496989a761657d9e79c317e26738c46)) +* add credentials authentication ([#1](https://github.com/homarr-labs/homarr/issues/1)) ([3cedb7f](https://github.com/homarr-labs/homarr/commit/3cedb7fba5aade5e176002453300779d6348a0b4)) +* add crud for integrations ([#11](https://github.com/homarr-labs/homarr/issues/11)) ([367beb6](https://github.com/homarr-labs/homarr/commit/367beb6759b54caaa8d3a2c723d5202626811976)) +* add custom css for board and custom classes in advanced options for items ([#512](https://github.com/homarr-labs/homarr/issues/512)) ([26b1c4a](https://github.com/homarr-labs/homarr/commit/26b1c4a3199c59e1b5eb3529da74180a455fa09f)) +* add dashdot integration ([#1541](https://github.com/homarr-labs/homarr/issues/1541)) ([84e5002](https://github.com/homarr-labs/homarr/commit/84e500279d5cc2db696365da46cf405c7a9fd06f)) +* add docker actions ([#752](https://github.com/homarr-labs/homarr/issues/752)) ([95101e3](https://github.com/homarr-labs/homarr/commit/95101e34ed0cc5134a7cb15fd0ab56c5f4b5a14e)) +* add docker container table ([#520](https://github.com/homarr-labs/homarr/issues/520)) ([dd2937a](https://github.com/homarr-labs/homarr/commit/dd2937a0d6106ce241cc5d8f25fc581c717604f1)) +* add duplication action for items ([#926](https://github.com/homarr-labs/homarr/issues/926)) ([81946e5](https://github.com/homarr-labs/homarr/commit/81946e50a9f643826f6c75ce2de54f92b74819bc)) +* add dynamic breadcrumb ([#706](https://github.com/homarr-labs/homarr/issues/706)) ([4e1bbf2](https://github.com/homarr-labs/homarr/commit/4e1bbf2ae64e951c62bb3a86787cecc1e2d22da9)) +* add dynamic section ([#842](https://github.com/homarr-labs/homarr/issues/842)) ([9ce172e](https://github.com/homarr-labs/homarr/commit/9ce172e78a142be71cfae8fdb581987fec9b78f0)) +* add edit user page ([#173](https://github.com/homarr-labs/homarr/issues/173)) ([41b99f1](https://github.com/homarr-labs/homarr/commit/41b99f191c6559bca49c7c3c3a13553c7698b781)) +* add env variable to disable db migrations on startup ([#1179](https://github.com/homarr-labs/homarr/issues/1179)) ([a30be7b](https://github.com/homarr-labs/homarr/commit/a30be7bc1e3beea0171c81ce9ec406ecc3c65e74)) +* add error page for docker tools page ([#1655](https://github.com/homarr-labs/homarr/issues/1655)) ([6031191](https://github.com/homarr-labs/homarr/commit/60311918ce31ec9ae84cadbc450fc5732f173536)) +* Add ErrorDisplay component ([245c2f4](https://github.com/homarr-labs/homarr/commit/245c2f483c36e197da4e8ff2a2fe1d58e2916786)) +* add everyone group ([#1322](https://github.com/homarr-labs/homarr/issues/1322)) ([2f1c800](https://github.com/homarr-labs/homarr/commit/2f1c8008447175697dfd3a814316665ed039713f)) +* add first day of week user setting ([#1249](https://github.com/homarr-labs/homarr/issues/1249)) ([ab1744c](https://github.com/homarr-labs/homarr/commit/ab1744ce20fd0df8c21361e3df0d65c9ab63c014)) +* add healthchecks ([#1187](https://github.com/homarr-labs/homarr/issues/1187)) ([08c6303](https://github.com/homarr-labs/homarr/commit/08c6303fa64a45580ef9ae41a7b1c0ea13266ecd)) +* add hero banner ([#463](https://github.com/homarr-labs/homarr/issues/463)) ([87fe03d](https://github.com/homarr-labs/homarr/commit/87fe03dd009be451981f99910d8f88129ecde9d1)) +* add home board for users ([#505](https://github.com/homarr-labs/homarr/issues/505)) ([7e339c0](https://github.com/homarr-labs/homarr/commit/7e339c09c86cafef56ea3bf915c8665b9e6e0c95)) +* add homeassistant integration ([#578](https://github.com/homarr-labs/homarr/issues/578)) ([2e782ae](https://github.com/homarr-labs/homarr/commit/2e782ae4428cc27024c29d58530fde86a65c87bd)) +* add hotkeys ([#986](https://github.com/homarr-labs/homarr/issues/986)) ([7521ef0](https://github.com/homarr-labs/homarr/commit/7521ef0519033fc4ddd51f03f46281417aa05b76)) +* add i18n translated form errors ([#509](https://github.com/homarr-labs/homarr/issues/509)) ([dfed804](https://github.com/homarr-labs/homarr/commit/dfed804f65003f715ed0bf699de39b4c8c63d63b)) +* add iframe widget ([#291](https://github.com/homarr-labs/homarr/issues/291)) ([8f48971](https://github.com/homarr-labs/homarr/commit/8f4897186c827f327d0823b619cd3ca4df859229)) +* add import for config files from oldmarr ([#1019](https://github.com/homarr-labs/homarr/issues/1019)) ([5404ceb](https://github.com/homarr-labs/homarr/commit/5404cebf5b04c5a93249c5674607640f70b798d3)) +* add improved search ([#1051](https://github.com/homarr-labs/homarr/issues/1051)) ([ce1ef3c](https://github.com/homarr-labs/homarr/commit/ce1ef3cbe761cbed9843eb4881758a30ac934fc1)) +* add integration access check to middlewares ([#756](https://github.com/homarr-labs/homarr/issues/756)) ([46943b1](https://github.com/homarr-labs/homarr/commit/46943b147ae08be3d79cce73243eaca4cba2959f)) +* add integration access settings ([#725](https://github.com/homarr-labs/homarr/issues/725)) ([408cdeb](https://github.com/homarr-labs/homarr/commit/408cdeb5c32735a9f78343818bb6f91eb1c8daee)) +* add jellyfin integration ([#672](https://github.com/homarr-labs/homarr/issues/672)) ([bb8640b](https://github.com/homarr-labs/homarr/commit/bb8640b1621f6a3809465c0187f99a8bcae473ed)), closes [#655](https://github.com/homarr-labs/homarr/issues/655) +* add job on start option for icons updater ([#442](https://github.com/homarr-labs/homarr/issues/442)) ([7b31684](https://github.com/homarr-labs/homarr/commit/7b31684c84aeaade6f370337821bea2d2bb9efee)) +* add ldap and oidc sso ([#500](https://github.com/homarr-labs/homarr/issues/500)) ([dc75ffb](https://github.com/homarr-labs/homarr/commit/dc75ffb9e65a6ea9479fae36558a5915578a83a6)) +* add lidarr integration ([#1433](https://github.com/homarr-labs/homarr/issues/1433)) ([ed74604](https://github.com/homarr-labs/homarr/commit/ed74604a547528a69d0572fe45e6482524ef1837)) +* add login and logout ([#436](https://github.com/homarr-labs/homarr/issues/436)) ([51aaab2](https://github.com/homarr-labs/homarr/commit/51aaab2f23f6a5a20fb5fc42bf8f9f79e017643e)) +* add logout redirect url ([#954](https://github.com/homarr-labs/homarr/issues/954)) ([13e0996](https://github.com/homarr-labs/homarr/commit/13e09968d928bc5e255dd3f93eca3d3e42f1b144)) +* add management pages ([#12](https://github.com/homarr-labs/homarr/issues/12)) ([2809e01](https://github.com/homarr-labs/homarr/commit/2809e01b03bf939aaecdce8007ece9322688061a)) +* add manifest ([#1309](https://github.com/homarr-labs/homarr/issues/1309)) ([727f104](https://github.com/homarr-labs/homarr/commit/727f10448f55d7dc7b9d4a227b34d7351816918d)) +* add media management ([#1337](https://github.com/homarr-labs/homarr/issues/1337)) ([db198c6](https://github.com/homarr-labs/homarr/commit/db198c6dab64b1dd299e6ed15a29ecb42bc409b6)) +* add media requests widget ([#774](https://github.com/homarr-labs/homarr/issues/774)) ([acbb834](https://github.com/homarr-labs/homarr/commit/acbb834889ae5a9161e609bff6a20d1e1a6258f3)) +* add member sync between groups of ldap and homarr ([#1149](https://github.com/homarr-labs/homarr/issues/1149)) ([6133309](https://github.com/homarr-labs/homarr/commit/61333094dff53cb4dea79f8dfffd3f9d6ee0ce1b)) +* add million-lint ([#607](https://github.com/homarr-labs/homarr/issues/607)) ([94984ac](https://github.com/homarr-labs/homarr/commit/94984ac11ba158563e8653d42d7c1f0b79bff0ea)) +* add more group permissions ([#1453](https://github.com/homarr-labs/homarr/issues/1453)) ([0ee343b](https://github.com/homarr-labs/homarr/commit/0ee343b99ecbb44140df8c3c59971108f13b3dce)) +* add mysql support ([#212](https://github.com/homarr-labs/homarr/issues/212)) ([24ec13c](https://github.com/homarr-labs/homarr/commit/24ec13c2ab76f73d4e18f1f4cc9ea369439b105d)) +* add nestjs app ([#172](https://github.com/homarr-labs/homarr/issues/172)) ([9440d04](https://github.com/homarr-labs/homarr/commit/9440d04261f6597c021fbb7a4eb6ee441bc8d41c)) +* add nestjs replacement, remove nestjs ([#285](https://github.com/homarr-labs/homarr/issues/285)) ([1936596](https://github.com/homarr-labs/homarr/commit/1936596c048552f1730a02b1e5c03aed6f9d0fb6)) +* add next-international translations ([#2](https://github.com/homarr-labs/homarr/issues/2)) ([a082f70](https://github.com/homarr-labs/homarr/commit/a082f704704bea127014216baeb914e9c8fe09f6)) +* add nginx proxy ([#1073](https://github.com/homarr-labs/homarr/issues/1073)) ([cd46198](https://github.com/homarr-labs/homarr/commit/cd4619845b83dd7d5bcd039b7ddeaf023eb42a84)) +* add not found pages for boards ([#1671](https://github.com/homarr-labs/homarr/issues/1671)) ([8e4d67c](https://github.com/homarr-labs/homarr/commit/8e4d67c3eb49f7ccbd7e87efa75dfe1e4665bf3f)) +* add notebook widget ([#294](https://github.com/homarr-labs/homarr/issues/294)) ([6b1879c](https://github.com/homarr-labs/homarr/commit/6b1879cbb1d5129b8960a5dec9880f4951c0222e)) +* add notes for creation of apps and integrations in widget edit modal ([#1297](https://github.com/homarr-labs/homarr/issues/1297)) ([e99fd64](https://github.com/homarr-labs/homarr/commit/e99fd648822f61b4ad7b3793875df69348a3e0c8)) +* add onboarding with oldmarr import ([#1606](https://github.com/homarr-labs/homarr/issues/1606)) ([6de74d9](https://github.com/homarr-labs/homarr/commit/6de74d952560275faf546c2720f71dddbe1fe399)) +* add password input field ([#160](https://github.com/homarr-labs/homarr/issues/160)) ([c6c8778](https://github.com/homarr-labs/homarr/commit/c6c87783979b1053fd6068920c412c20547bab69)) +* add password requirements ([#988](https://github.com/homarr-labs/homarr/issues/988)) ([2d155fa](https://github.com/homarr-labs/homarr/commit/2d155fa0c48d63fe376d52e2c5403c8ec1130db6)) +* add permission section to create user page ([#1524](https://github.com/homarr-labs/homarr/issues/1524)) ([1fc48f9](https://github.com/homarr-labs/homarr/commit/1fc48f9db05935bc3298f9251b564ed539c48312)) +* add pi hole summary integration ([#521](https://github.com/homarr-labs/homarr/issues/521)) ([d57b771](https://github.com/homarr-labs/homarr/commit/d57b771a177511b878c0eada1d3002b52acdc6fb)) +* add prettier packagejson plugin ([#1577](https://github.com/homarr-labs/homarr/issues/1577)) ([a53a2cd](https://github.com/homarr-labs/homarr/commit/a53a2cdd34a46d6442c030192b449a855b69fca3)) +* add preview to icon picker ([#914](https://github.com/homarr-labs/homarr/issues/914)) ([ca1ecdf](https://github.com/homarr-labs/homarr/commit/ca1ecdf84811c58e4dff372fab42e64ab1791f06)) +* add readarr integration ([#1446](https://github.com/homarr-labs/homarr/issues/1446)) ([563c5d8](https://github.com/homarr-labs/homarr/commit/563c5d8f3c0dc5b7dcedadf7fa22c690c131a5c8)) +* add real time logger page ([#276](https://github.com/homarr-labs/homarr/issues/276)) ([c82915c](https://github.com/homarr-labs/homarr/commit/c82915c6dcaef8edffc67b82c97ba87e4597852a)) +* add redis ([#242](https://github.com/homarr-labs/homarr/issues/242)) ([1825e56](https://github.com/homarr-labs/homarr/commit/1825e563493a443039a5d0a8fa6d0b7ce3ef08b0)) +* add redis cache channel ([e05deef](https://github.com/homarr-labs/homarr/commit/e05deef6e28c7bbddda154d3d23f5325e85f3571)) +* add refresh button to docker containers table ([#913](https://github.com/homarr-labs/homarr/issues/913)) ([b53a2b6](https://github.com/homarr-labs/homarr/commit/b53a2b6b78f73f86ecff24cbf40b91e0f4ca55b0)) +* add rss widget ([#760](https://github.com/homarr-labs/homarr/issues/760)) ([15d9327](https://github.com/homarr-labs/homarr/commit/15d9327d465d1c522d9182027adaf27727a95b4e)) +* add server settings ([#487](https://github.com/homarr-labs/homarr/issues/487)) ([9191617](https://github.com/homarr-labs/homarr/commit/919161798ee6c5c2070632920c9dfc3699ab1f93)) +* add server settings for default board, default color scheme and default locale ([#1373](https://github.com/homarr-labs/homarr/issues/1373)) ([326b769](https://github.com/homarr-labs/homarr/commit/326b769c23f6619c7d6edd0cecedccdf6d641dde)) +* add session expiry ([#951](https://github.com/homarr-labs/homarr/issues/951)) ([6dafbaa](https://github.com/homarr-labs/homarr/commit/6dafbaae48f17ff519723fe33fc89034b10e8f1b)) +* add simple app ping ([#580](https://github.com/homarr-labs/homarr/issues/580)) ([d7ecdf5](https://github.com/homarr-labs/homarr/commit/d7ecdf55672e05e90424bed964644091b1af6499)) +* Add Simple-Icons and Selfh.st collections ([#1118](https://github.com/homarr-labs/homarr/issues/1118)) ([9fb6e67](https://github.com/homarr-labs/homarr/commit/9fb6e67ed33264f877ba819240e00d8fc8dbb984)) +* add support for all languages from old homarr ([#1394](https://github.com/homarr-labs/homarr/issues/1394)) ([0ff7c89](https://github.com/homarr-labs/homarr/commit/0ff7c8903b3c23ee286a0e3d68287927e03ff3e0)) +* add support for app url variables ([#915](https://github.com/homarr-labs/homarr/issues/915)) ([c4c4d41](https://github.com/homarr-labs/homarr/commit/c4c4d41e4d7c37d498ba25c91a734a9d7f66f233)) +* add support for multiple integration kind options ([#127](https://github.com/homarr-labs/homarr/issues/127)) ([f1aa422](https://github.com/homarr-labs/homarr/commit/f1aa42261446bcc4bd16b47ed0c1d5cd279a2e48)) +* add support for should hide option i widget edit modal ([#78](https://github.com/homarr-labs/homarr/issues/78)) ([16442bc](https://github.com/homarr-labs/homarr/commit/16442bc379c1d418080947fbd86a4bb14639e90e)) +* add tasks page ([#692](https://github.com/homarr-labs/homarr/issues/692)) ([08d571a](https://github.com/homarr-labs/homarr/commit/08d571ad74c0c97313664b31bf2d1ce83d91629b)) +* add tdarr integration ([#1657](https://github.com/homarr-labs/homarr/issues/1657)) ([032509e](https://github.com/homarr-labs/homarr/commit/032509e4623d7bab3a000a308cb21fc487c45487)) +* add trpc websocket ([#205](https://github.com/homarr-labs/homarr/issues/205)) ([4f375cb](https://github.com/homarr-labs/homarr/commit/4f375cbe6d1b82322e0e8eaeea9db60be083c84e)) +* add undici fetch interceptor ([#687](https://github.com/homarr-labs/homarr/issues/687)) ([508369c](https://github.com/homarr-labs/homarr/commit/508369cb0bb61dadbc2c0b06f03e08581bc7d8ae)) +* add update indicator ([#1626](https://github.com/homarr-labs/homarr/issues/1626)) ([dd9d8b5](https://github.com/homarr-labs/homarr/commit/dd9d8b52610aefe4dbf19f20117ea51264525bcb)) +* add user avatar menu ([#80](https://github.com/homarr-labs/homarr/issues/80)) ([08fa338](https://github.com/homarr-labs/homarr/commit/08fa338abbdff3bb3f7cfc96bc328ecb4a49c584)) +* add user groups ([#376](https://github.com/homarr-labs/homarr/issues/376)) ([036925b](https://github.com/homarr-labs/homarr/commit/036925bf78ec50afe8455efdc270ee4e503a0e03)) +* add user invite management ([#338](https://github.com/homarr-labs/homarr/issues/338)) ([621f6c8](https://github.com/homarr-labs/homarr/commit/621f6c81ae8689f6efc9ac141e8bcbf7fe35eb81)) +* add user invite registration ([#477](https://github.com/homarr-labs/homarr/issues/477)) ([94af21a](https://github.com/homarr-labs/homarr/commit/94af21abbfb36b1804d86d89155af720055de588)) +* add user management ([#134](https://github.com/homarr-labs/homarr/issues/134)) ([b4749e7](https://github.com/homarr-labs/homarr/commit/b4749e7091649815f2918b81d3c79b0216ece5d2)) +* add user setting for home board ([#956](https://github.com/homarr-labs/homarr/issues/956)) ([f327837](https://github.com/homarr-labs/homarr/commit/f327837d82149c563b07e1d42850356930f20e50)) +* add username validation to prevent duplicate ([781247d](https://github.com/homarr-labs/homarr/commit/781247de5141f4b0532801194ac904763db7da39)) +* add validation to widget edit modal inputs ([#879](https://github.com/homarr-labs/homarr/issues/879)) ([9cb6200](https://github.com/homarr-labs/homarr/commit/9cb6200895a0d44e87f59cdaf19432fb8312f8bf)) +* add video widget ([#287](https://github.com/homarr-labs/homarr/issues/287)) ([82e9887](https://github.com/homarr-labs/homarr/commit/82e9887f36a370594f258d8e6f60cda57593b2b7)) +* Add VOLUME instruction to `Dockerfile` ([#527](https://github.com/homarr-labs/homarr/issues/527)) ([5a9e8ed](https://github.com/homarr-labs/homarr/commit/5a9e8edf70b91933afbd0b4564fda3ab25fdbdd5)) +* add weather widget ([#286](https://github.com/homarr-labs/homarr/issues/286)) ([80d2d48](https://github.com/homarr-labs/homarr/commit/80d2d485b862f6c95fa1eb81ff96cb45d9b147b1)) +* add web search engines ([#290](https://github.com/homarr-labs/homarr/issues/290)) ([35ca732](https://github.com/homarr-labs/homarr/commit/35ca732744752b54b6318e17319d9b8ac950fda8)) +* Add widget integration option ([#14](https://github.com/homarr-labs/homarr/issues/14)) ([1740450](https://github.com/homarr-labs/homarr/commit/1740450648fc5c3915cd71b493a8523305f33703)) +* add widget preview pages ([#9](https://github.com/homarr-labs/homarr/issues/9)) ([7828975](https://github.com/homarr-labs/homarr/commit/782897527f489889f8b6f46ec577a298a0714953)) +* add widget server loader ([#16](https://github.com/homarr-labs/homarr/issues/16)) ([975f912](https://github.com/homarr-labs/homarr/commit/975f9123dd4d509e2b777d8af8d74f38ebc59aad)) +* add winston logger ([#143](https://github.com/homarr-labs/homarr/issues/143)) ([3d50f81](https://github.com/homarr-labs/homarr/commit/3d50f8165f0d27e9fe7b517cffa5d1950eca7ab8)) +* add winston logger ([#77](https://github.com/homarr-labs/homarr/issues/77)) ([34875df](https://github.com/homarr-labs/homarr/commit/34875dfd154f9e9e3a8ce5c5bc4d14e757b4b14d)) +* AdGuard Home integration ([#929](https://github.com/homarr-labs/homarr/issues/929)) ([4471260](https://github.com/homarr-labs/homarr/commit/44712608b7e0dfcbaf5d36c40792b04f2edec8d7)) +* allow no secrets for integration ([#856](https://github.com/homarr-labs/homarr/issues/856)) ([508fcb9](https://github.com/homarr-labs/homarr/commit/508fcb9861d56f84d027fc8c456d8841486fdf72)) +* App tile scalability ([#645](https://github.com/homarr-labs/homarr/issues/645)) ([28927cf](https://github.com/homarr-labs/homarr/commit/28927cfa2802c6335487638b5ce4d7133f2e4423)) +* approve before automerge ([3df6dcf](https://github.com/homarr-labs/homarr/commit/3df6dcfbe7b1b499dbd6ddf536ae509286afe21b)) +* board access group permissions ([#422](https://github.com/homarr-labs/homarr/issues/422)) ([b1e065f](https://github.com/homarr-labs/homarr/commit/b1e065f1da0fc0c4992d0de8f6ed87a9adef1d24)) +* board settings ([#137](https://github.com/homarr-labs/homarr/issues/137)) ([bb02163](https://github.com/homarr-labs/homarr/commit/bb02163e25e64c13e4f36df21fa90ff33483cac6)) +* cannot change username to the current one ([0ae8a75](https://github.com/homarr-labs/homarr/commit/0ae8a75a5ef38c85ca869cadbed9542c2993a3df)) +* change visibility in item options based on selected integration kinds ([#949](https://github.com/homarr-labs/homarr/issues/949)) ([25452ff](https://github.com/homarr-labs/homarr/commit/25452ff063383397af6b5e41984657f9eb68e801)) +* Clock widget and dayjs locale standard ([#79](https://github.com/homarr-labs/homarr/issues/79)) ([edcba9c](https://github.com/homarr-labs/homarr/commit/edcba9ceb62880196dac902e0a91b1dbdd0c45f1)) +* Clock widget scalability ([#644](https://github.com/homarr-labs/homarr/issues/644)) ([bac09d8](https://github.com/homarr-labs/homarr/commit/bac09d8be59eea7f59713fead9e5310b34cfa8aa)) +* date format on weather widget ([#1443](https://github.com/homarr-labs/homarr/issues/1443)) ([c51c5db](https://github.com/homarr-labs/homarr/commit/c51c5db3d73db8656f4d55921b5b664b8c27134e)) +* DNS Hole summary Scalability ([#646](https://github.com/homarr-labs/homarr/issues/646)) ([0710425](https://github.com/homarr-labs/homarr/commit/0710425e787aec1bcd90d3ba8dae71c8c97959ae)) +* dnshole controls widget ([#867](https://github.com/homarr-labs/homarr/issues/867)) ([65c6854](https://github.com/homarr-labs/homarr/commit/65c6854e4426350b196b1888c952d961c03c2b23)) +* DnsHole feature parity with oldmarr ([#1145](https://github.com/homarr-labs/homarr/issues/1145)) ([36915d9](https://github.com/homarr-labs/homarr/commit/36915d95fe45964f0291fb8c9cbc46ffecdf2681)) +* **docker:** add encryption key generation for integration secrets ([#1202](https://github.com/homarr-labs/homarr/issues/1202)) ([52b45d8](https://github.com/homarr-labs/homarr/commit/52b45d835db99b5e6b950a2adfb6e21665c8ccff)) +* downloads widget ([#844](https://github.com/homarr-labs/homarr/issues/844)) ([2535192](https://github.com/homarr-labs/homarr/commit/2535192b2cfc1c4acc42b31a59f90989236ea2c2)) +* implement board access control ([#349](https://github.com/homarr-labs/homarr/issues/349)) ([7ab9dc2](https://github.com/homarr-labs/homarr/commit/7ab9dc250184947b1f1a071a0cb7bce63ce95c96)) +* implement openapi ([#482](https://github.com/homarr-labs/homarr/issues/482)) ([f0cd45c](https://github.com/homarr-labs/homarr/commit/f0cd45c81385720f68693f8d3481466fc147cd61)) +* improve metadata ([#1308](https://github.com/homarr-labs/homarr/issues/1308)) ([0df7cb5](https://github.com/homarr-labs/homarr/commit/0df7cb5c25441700616d268fac5e64068542d080)) +* improve user init setup ([#643](https://github.com/homarr-labs/homarr/issues/643)) ([3a3a825](https://github.com/homarr-labs/homarr/commit/3a3a8251bdb65f07e109af83b639efabbd1404a5)) +* indexer manager widget ([#1057](https://github.com/homarr-labs/homarr/issues/1057)) ([08d4472](https://github.com/homarr-labs/homarr/commit/08d4472d8b612e11a8b4e5f09952a788e7bcdf8a)), closes [#1055](https://github.com/homarr-labs/homarr/issues/1055) +* integrate crowdin [#1402](https://github.com/homarr-labs/homarr/issues/1402) ([#1599](https://github.com/homarr-labs/homarr/issues/1599)) ([096f034](https://github.com/homarr-labs/homarr/commit/096f03432cfca75bc2740f65d7d6cb6fed4c4eaa)) +* language selector ([#484](https://github.com/homarr-labs/homarr/issues/484)) ([31c2694](https://github.com/homarr-labs/homarr/commit/31c26941857b4eac8e69ccb68bc4c00cd1073806)) +* log elapsed cron job time ([#742](https://github.com/homarr-labs/homarr/issues/742)) ([1cf119c](https://github.com/homarr-labs/homarr/commit/1cf119c76827c22dcac9f2417b6f65b64cd43e26)) +* log sql queries ([#444](https://github.com/homarr-labs/homarr/issues/444)) ([dc0184a](https://github.com/homarr-labs/homarr/commit/dc0184af071446e299407a2b6347852d52bdd17f)) +* make notifications optional ([e438bac](https://github.com/homarr-labs/homarr/commit/e438bac0f5dd7d487aae054802b5255612749252)) +* OMV integration & health monitoring widget ([#1142](https://github.com/homarr-labs/homarr/issues/1142)) ([0f56dc1](https://github.com/homarr-labs/homarr/commit/0f56dc1ecd03d6d6fe2305de85650f2b105e2169)) +* plex integration ([#1342](https://github.com/homarr-labs/homarr/issues/1342)) ([cf9b058](https://github.com/homarr-labs/homarr/commit/cf9b0581a486b3d6b1207e8a612c9fe4665c6d49)) +* populate integration name for new integrations automatically ([#1296](https://github.com/homarr-labs/homarr/issues/1296)) ([a0cc31d](https://github.com/homarr-labs/homarr/commit/a0cc31da700defc9a4f5c4210962571cbfe2b362)) +* pretty-print-error to print errors in console ([#1596](https://github.com/homarr-labs/homarr/issues/1596)) ([71f4f8c](https://github.com/homarr-labs/homarr/commit/71f4f8c4c85eb70533bed3ed86b6655e99cc2bb7)) +* Prowlarr integration ([#965](https://github.com/homarr-labs/homarr/issues/965)) ([6ff3640](https://github.com/homarr-labs/homarr/commit/6ff36405ba26ab27387094182885a99bf1ecb30d)) +* radarr integration ([#1053](https://github.com/homarr-labs/homarr/issues/1053)) ([e88854c](https://github.com/homarr-labs/homarr/commit/e88854c0e5b14c356f520c616b369d118ea3ddf7)) +* radarr release type to calendar widget ([#1256](https://github.com/homarr-labs/homarr/issues/1256)) ([98b62a9](https://github.com/homarr-labs/homarr/commit/98b62a9f919ef18f891e115f3dec31c7f1e49a44)) +* read all packages on about page ([#391](https://github.com/homarr-labs/homarr/issues/391)) ([16e42d6](https://github.com/homarr-labs/homarr/commit/16e42d654dbf8cf54757e49cc1c73ea1fa69d8a7)) +* remove manual flag to pushing image ([9013d5d](https://github.com/homarr-labs/homarr/commit/9013d5dbf01a7c60e5a427cfcebea7a332deb5d2)) +* replace home page with home board ([#1530](https://github.com/homarr-labs/homarr/issues/1530)) ([9fb14df](https://github.com/homarr-labs/homarr/commit/9fb14df2103db720cb6e5333b8afed5c1e730de6)) +* reset password cli ([#903](https://github.com/homarr-labs/homarr/issues/903)) ([7fa5e70](https://github.com/homarr-labs/homarr/commit/7fa5e70d5b5e4e6cded08f343f5db0f42e8be324)) +* restrict non credential provider interactions ([#871](https://github.com/homarr-labs/homarr/issues/871)) ([6f7327b](https://github.com/homarr-labs/homarr/commit/6f7327b77478c567b478c2c61b0a09400e426678)) +* RTL option to RSS widget ([#1247](https://github.com/homarr-labs/homarr/issues/1247)) ([9a7e845](https://github.com/homarr-labs/homarr/commit/9a7e8450106aa5f61db9e3360221bd8ac168daf6)) +* show creator on board page ([#440](https://github.com/homarr-labs/homarr/issues/440)) ([5d30301](https://github.com/homarr-labs/homarr/commit/5d30301b95a8b1e6129d97a6a66cbfb417407caf)) +* **spotlight:** add support for custom search-engines ([#1200](https://github.com/homarr-labs/homarr/issues/1200)) ([4c9471e](https://github.com/homarr-labs/homarr/commit/4c9471e6086c354ec4383f22a7b8020c5aa8974d)) +* support arm64 ([#1022](https://github.com/homarr-labs/homarr/issues/1022)) ([0c65727](https://github.com/homarr-labs/homarr/commit/0c657276a53aa77d6cc37435e61907574320e324)) +* test integration connection ([#669](https://github.com/homarr-labs/homarr/issues/669)) ([f92aeba](https://github.com/homarr-labs/homarr/commit/f92aeba403ec22e2a3219550b51191ae82bac000)) +* use consistent line ending ([#1407](https://github.com/homarr-labs/homarr/issues/1407)) ([0c067c4](https://github.com/homarr-labs/homarr/commit/0c067c4e6f36d741edf7c88de847585fefd54b64)) +* use different tag name ([ff847f0](https://github.com/homarr-labs/homarr/commit/ff847f091054c38015f45dfd1ee88e06116f53ad)) +* use gh app for merging ([82caec4](https://github.com/homarr-labs/homarr/commit/82caec402a4f33d0217b9d5e02140d4857dbb0ce)) +* use password input ([#163](https://github.com/homarr-labs/homarr/issues/163)) ([2a83df3](https://github.com/homarr-labs/homarr/commit/2a83df348555de884a9419ecf6e7ecdc76272deb)) +* user preferences ([#470](https://github.com/homarr-labs/homarr/issues/470)) ([db01301](https://github.com/homarr-labs/homarr/commit/db013018453ba6d67a229d5b9852e85e61a6760d)) +* user setting ping icons ([#1277](https://github.com/homarr-labs/homarr/issues/1277)) ([3486876](https://github.com/homarr-labs/homarr/commit/348687670d18062254e8089572f824f33a6f0894)) +* weather widget scalable ([#574](https://github.com/homarr-labs/homarr/issues/574)) ([cfd8b32](https://github.com/homarr-labs/homarr/commit/cfd8b328b40352c4f517853b6f019042ddf57549)) + +### Bug Fixes + +* actions user has no permission to are shown in spotlight ([#1452](https://github.com/homarr-labs/homarr/issues/1452)) ([04895da](https://github.com/homarr-labs/homarr/commit/04895da08a72864a55d6bb09524588ba0d9a06c1)) +* add beforeunload logic for board in edit mode ([#1531](https://github.com/homarr-labs/homarr/issues/1531)) ([225356c](https://github.com/homarr-labs/homarr/commit/225356cc4f49a8a8178f9d7dffc3283bc641b3d0)) +* add missing tags ([f23831b](https://github.com/homarr-labs/homarr/commit/f23831be5ec257775ca9ce116a50f025cac65c2d)) +* add persists credentials false to checkout of release pipeline ([#1691](https://github.com/homarr-labs/homarr/issues/1691)) ([daf7ea5](https://github.com/homarr-labs/homarr/commit/daf7ea56c5ce05803efc475ad64c5abb6a0784ea)) +* add rtl compliance for symbols [#366](https://github.com/homarr-labs/homarr/issues/366) ([#406](https://github.com/homarr-labs/homarr/issues/406)) ([0278e3a](https://github.com/homarr-labs/homarr/commit/0278e3a854455a48c53ab394d4c4e65734f535ca)) +* add sharp ([#241](https://github.com/homarr-labs/homarr/issues/241)) ([0440af3](https://github.com/homarr-labs/homarr/commit/0440af3566ce7e57eaedd6921c16143943647bd4)) +* add subscription to health monitoring widget ([#1210](https://github.com/homarr-labs/homarr/issues/1210)) ([ce67fcd](https://github.com/homarr-labs/homarr/commit/ce67fcd57cd56fe68105c269a9f2377bbc89e61b)) +* adding volume /appdata removes created directories ([#1445](https://github.com/homarr-labs/homarr/issues/1445)) ([fe4dfc4](https://github.com/homarr-labs/homarr/commit/fe4dfc484bcc5da8d3901d042adc5d3cf3ea9fbc)) +* alert that certain fields in user settings are disabled is always shown ([#928](https://github.com/homarr-labs/homarr/issues/928)) ([9258c39](https://github.com/homarr-labs/homarr/commit/9258c397e0689bf46969614f3c634b5af20a2d8c)) +* Allow username to be capitalized on basic credentials login ([#1585](https://github.com/homarr-labs/homarr/issues/1585)) ([a1a6dc9](https://github.com/homarr-labs/homarr/commit/a1a6dc9d6e345ff102d69164d4bf2d7020db0ea4)) +* api keys authentication does not work [#1511](https://github.com/homarr-labs/homarr/issues/1511) ([#1512](https://github.com/homarr-labs/homarr/issues/1512)) ([72eda1f](https://github.com/homarr-labs/homarr/commit/72eda1f225cece3d317c66b4b98a481328962d63)) +* auth broken cause of consistent table column rename ([#1532](https://github.com/homarr-labs/homarr/issues/1532)) ([4a94d60](https://github.com/homarr-labs/homarr/commit/4a94d602c0cce7796cde7c08a5670e045452c2c5)) +* auto-merge crowdin pr not working ([#1664](https://github.com/homarr-labs/homarr/issues/1664)) ([f330c7e](https://github.com/homarr-labs/homarr/commit/f330c7e4f1a8e097e2f594c47061f98c7c9e0034)) +* auto-merge for crowdin download pull request not working ([#1661](https://github.com/homarr-labs/homarr/issues/1661)) ([5bdc669](https://github.com/homarr-labs/homarr/commit/5bdc669e07c788f3b47009a4f5c3c2c785dda111)) +* base branch for semver ([a8748fa](https://github.com/homarr-labs/homarr/commit/a8748fa439c481d7238a32b99184e9fce667a709)) +* cache is not exportet from react ([#417](https://github.com/homarr-labs/homarr/issues/417)) ([fba767b](https://github.com/homarr-labs/homarr/commit/fba767bde3d17c09d563ccea352cd8e4171e84f8)) +* change docker concurrency group to allow multiple deployments to different branches ([#1687](https://github.com/homarr-labs/homarr/issues/1687)) ([93abe8f](https://github.com/homarr-labs/homarr/commit/93abe8f6a2bfe012b6c03c7994e5334f22b6e5e8)) +* change node-version for composite setup action to 22, remove unnecessary installation of node from docker deployment ([#1429](https://github.com/homarr-labs/homarr/issues/1429)) ([319fb47](https://github.com/homarr-labs/homarr/commit/319fb477444bae5cd4c847af9ebf9e35359fbb03)) +* change permission for github action to contents write ([#1689](https://github.com/homarr-labs/homarr/issues/1689)) ([0f029b3](https://github.com/homarr-labs/homarr/commit/0f029b384d1699ea8ee784651b97b88fd64613c6)) +* color scheme manager should use cookie and not session value ([#1329](https://github.com/homarr-labs/homarr/issues/1329)) ([799d6c5](https://github.com/homarr-labs/homarr/commit/799d6c5d4a59c65d3e2f902843dfc86910b8496f)) +* confirm not selected by default in confirm modal ([#1232](https://github.com/homarr-labs/homarr/issues/1232)) ([ac07504](https://github.com/homarr-labs/homarr/commit/ac0750452cd4788cba48d3af720240e063080fba)) +* container image always being on AMD64 arch ([#1173](https://github.com/homarr-labs/homarr/issues/1173)) ([65f2611](https://github.com/homarr-labs/homarr/commit/65f26117fc491958922cd863801cc049479766af)) +* controller is already closed trpc subscription observable error ([#743](https://github.com/homarr-labs/homarr/issues/743)) ([41dba7b](https://github.com/homarr-labs/homarr/commit/41dba7b516880098ae923d45f2065875cb6c70da)) +* correctly set pr description ([#778](https://github.com/homarr-labs/homarr/issues/778)) ([f58c38a](https://github.com/homarr-labs/homarr/commit/f58c38a1aa654acc474b492610452a9c38d20f42)) +* crash with no user in session ([547f75d](https://github.com/homarr-labs/homarr/commit/547f75d19cb08cd0eac6978cb9a6eb107a563edd)) +* create board submit button inverted ([0ee8c5a](https://github.com/homarr-labs/homarr/commit/0ee8c5ad91dfe70ef27af3fe9a47918bab23a665)) +* create user async is called twice ([7fa120c](https://github.com/homarr-labs/homarr/commit/7fa120c47490ab3e80fb8db0921d9afa3e12cfee)) +* credentials auth not working ([#1284](https://github.com/homarr-labs/homarr/issues/1284)) ([511c9a4](https://github.com/homarr-labs/homarr/commit/511c9a4dbbcaa3846bcd5a3dfe1827793e398ff4)) +* credentials login not working cause of cookie secure flag not possible for http ([#1421](https://github.com/homarr-labs/homarr/issues/1421)) ([cf5bcab](https://github.com/homarr-labs/homarr/commit/cf5bcab732924ef5b7a3eabf2d0a8760a59d6cb6)) +* db port validation for env variable wrong ([#1137](https://github.com/homarr-labs/homarr/issues/1137)) ([d01ddd6](https://github.com/homarr-labs/homarr/commit/d01ddd61b6fe3583412c7a553cfba8d32ae797a7)) +* default branch for tag compare ([#597](https://github.com/homarr-labs/homarr/issues/597)) ([7cc2736](https://github.com/homarr-labs/homarr/commit/7cc2736d68baaa5730e598b6c8e2cd55fa73711d)) +* defaultTitle invalid attribute on div ([#350](https://github.com/homarr-labs/homarr/issues/350)) ([4970c3a](https://github.com/homarr-labs/homarr/commit/4970c3a1b2545feb3bc20cc6605f8f16a28a8220)) +* deployment pipeline for docker not working ([#860](https://github.com/homarr-labs/homarr/issues/860)) ([90ef982](https://github.com/homarr-labs/homarr/commit/90ef982066b528e891bc3796256b2725ec1addf3)) +* **deps:** update dependency @auth/core to ^0.25.0 ([#29](https://github.com/homarr-labs/homarr/issues/29)) ([8bcbc45](https://github.com/homarr-labs/homarr/commit/8bcbc45943358d580712e0990ba2bb3c2c62d057)) +* **deps:** update dependency @auth/core to ^0.26.3 ([#54](https://github.com/homarr-labs/homarr/issues/54)) ([5cbd02b](https://github.com/homarr-labs/homarr/commit/5cbd02b142da68f067ef9831c6b47f117fbdc8e4)) +* **deps:** update dependency @auth/core to ^0.27.0 ([#89](https://github.com/homarr-labs/homarr/issues/89)) ([6c5e475](https://github.com/homarr-labs/homarr/commit/6c5e4752eaf7a07f9e80951541108643efb0faae)) +* **deps:** update dependency @auth/core to ^0.28.0 ([#169](https://github.com/homarr-labs/homarr/issues/169)) ([aa19139](https://github.com/homarr-labs/homarr/commit/aa19139cf7c4bb4ea6b57c3ca274fff533c2bb2a)) +* **deps:** update dependency @auth/core to ^0.28.1 ([#266](https://github.com/homarr-labs/homarr/issues/266)) ([c72f4bb](https://github.com/homarr-labs/homarr/commit/c72f4bb80de55c6a7dd94e142ce3b27c9073d33e)) +* **deps:** update dependency @auth/core to ^0.28.2 ([#292](https://github.com/homarr-labs/homarr/issues/292)) ([ba16ba1](https://github.com/homarr-labs/homarr/commit/ba16ba138209e843f1ee7304ebe1af138b6995fa)) +* **deps:** update dependency @auth/core to ^0.29.0 ([#327](https://github.com/homarr-labs/homarr/issues/327)) ([719d1cd](https://github.com/homarr-labs/homarr/commit/719d1cd845a3d6565c01d4f1846e9192038c1ce2)) +* **deps:** update dependency @auth/core to ^0.30.0 ([#358](https://github.com/homarr-labs/homarr/issues/358)) ([f6c0f3a](https://github.com/homarr-labs/homarr/commit/f6c0f3ab78f68cffc1ad2305c19f22b725b7a037)) +* **deps:** update dependency @auth/core to ^0.31.0 ([#473](https://github.com/homarr-labs/homarr/issues/473)) ([95ddd03](https://github.com/homarr-labs/homarr/commit/95ddd03763532658c620c50c698c14ed7cd01894)) +* **deps:** update dependency @auth/core to ^0.32.0 ([#603](https://github.com/homarr-labs/homarr/issues/603)) ([dc3b007](https://github.com/homarr-labs/homarr/commit/dc3b00736eabc4a65febb6ae9a8fd9779edb1cdf)) +* **deps:** update dependency @auth/core to ^0.33.0 ([#693](https://github.com/homarr-labs/homarr/issues/693)) ([171fe40](https://github.com/homarr-labs/homarr/commit/171fe40fd59ee1b21bf825a59b0f1792f627262f)) +* **deps:** update dependency @auth/core to ^0.34.0 ([#700](https://github.com/homarr-labs/homarr/issues/700)) ([9087f4b](https://github.com/homarr-labs/homarr/commit/9087f4bfdf263490b6d0e318e1af957dba493f09)) +* **deps:** update dependency @auth/core to ^0.34.1 ([#702](https://github.com/homarr-labs/homarr/issues/702)) ([05702be](https://github.com/homarr-labs/homarr/commit/05702bede88f86ef9014b8f7efa49b8d8a3ceca4)) +* **deps:** update dependency @auth/core to ^0.34.2 ([#876](https://github.com/homarr-labs/homarr/issues/876)) ([9181f11](https://github.com/homarr-labs/homarr/commit/9181f11b137f6327b558fabf6fe8b79de7ff345b)) +* **deps:** update dependency @auth/core to ^0.35.0 ([#1129](https://github.com/homarr-labs/homarr/issues/1129)) ([f9cc34c](https://github.com/homarr-labs/homarr/commit/f9cc34c12f1c8c3334f34a72322852a1e9e8e007)) +* **deps:** update dependency @auth/core to ^0.35.1 ([#1176](https://github.com/homarr-labs/homarr/issues/1176)) ([16e7f93](https://github.com/homarr-labs/homarr/commit/16e7f938bd2604cc2067466b56725ebe9f9743f9)) +* **deps:** update dependency @auth/core to ^0.35.2 ([#1180](https://github.com/homarr-labs/homarr/issues/1180)) ([f495383](https://github.com/homarr-labs/homarr/commit/f495383bcf2a725d82628067c19e763c84c8bdc1)) +* **deps:** update dependency @auth/core to ^0.35.3 ([#1193](https://github.com/homarr-labs/homarr/issues/1193)) ([1994a59](https://github.com/homarr-labs/homarr/commit/1994a5938d5cbb33a1e6cae0676d9350c9424f82)) +* **deps:** update dependency @auth/core to ^0.36.0 ([#1250](https://github.com/homarr-labs/homarr/issues/1250)) ([d0d2a82](https://github.com/homarr-labs/homarr/commit/d0d2a82a68f9155564d92ce925ac7d8cd80f42ee)) +* **deps:** update dependency @auth/core to ^0.37.0 ([#1272](https://github.com/homarr-labs/homarr/issues/1272)) ([8bcba35](https://github.com/homarr-labs/homarr/commit/8bcba350d58564b03cb2ff3296f8ddf2c77d0dae)) +* **deps:** update dependency @auth/core to ^0.37.1 ([#1323](https://github.com/homarr-labs/homarr/issues/1323)) ([dac2b50](https://github.com/homarr-labs/homarr/commit/dac2b5063bb892cdc5079a9957eb9199b6d62738)) +* **deps:** update dependency @auth/core to ^0.37.2 ([#1338](https://github.com/homarr-labs/homarr/issues/1338)) ([aa2d2f8](https://github.com/homarr-labs/homarr/commit/aa2d2f8c4b1b50e07cb68fb1bd76d6561fedb716)) +* **deps:** update dependency @auth/core to ^0.37.3 ([#1416](https://github.com/homarr-labs/homarr/issues/1416)) ([7a07f57](https://github.com/homarr-labs/homarr/commit/7a07f57d0c34fb2c5e98680b351254ab32e9a593)) +* **deps:** update dependency @auth/core to ^0.37.4 ([#1492](https://github.com/homarr-labs/homarr/issues/1492)) ([d4f0aa7](https://github.com/homarr-labs/homarr/commit/d4f0aa761d95cb2b7f72787b95b0033faba072c3)) +* **deps:** update dependency @auth/drizzle-adapter to ^0.5.0 ([#30](https://github.com/homarr-labs/homarr/issues/30)) ([191d773](https://github.com/homarr-labs/homarr/commit/191d773aaf55209d67be841e4f24f24e6439ca85)) +* **deps:** update dependency @auth/drizzle-adapter to ^0.6.3 ([#52](https://github.com/homarr-labs/homarr/issues/52)) ([6797cca](https://github.com/homarr-labs/homarr/commit/6797cca25945da5944966622c0cba5a9e0a263fa)) +* **deps:** update dependency @auth/drizzle-adapter to ^0.7.0 ([#90](https://github.com/homarr-labs/homarr/issues/90)) ([1139352](https://github.com/homarr-labs/homarr/commit/11393525d9bfc192818c1ef2d80c3d41f56fcca3)) +* **deps:** update dependency @auth/drizzle-adapter to ^0.8.0 ([#170](https://github.com/homarr-labs/homarr/issues/170)) ([50fd4c1](https://github.com/homarr-labs/homarr/commit/50fd4c17adfac217d7908d612fe10ee97171edac)) +* **deps:** update dependency @auth/drizzle-adapter to ^0.8.1 ([#267](https://github.com/homarr-labs/homarr/issues/267)) ([98a8eaa](https://github.com/homarr-labs/homarr/commit/98a8eaac0950e53864cb87ee722f353df6c56c56)) +* **deps:** update dependency @auth/drizzle-adapter to ^0.8.2 ([#293](https://github.com/homarr-labs/homarr/issues/293)) ([fbc69f6](https://github.com/homarr-labs/homarr/commit/fbc69f6078ddae657646247db77c425773ab5170)) +* **deps:** update dependency @auth/drizzle-adapter to ^0.9.0 ([#328](https://github.com/homarr-labs/homarr/issues/328)) ([7fb0dec](https://github.com/homarr-labs/homarr/commit/7fb0decd5bde0855a191c69f52f426d104bf7151)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.1.0 ([#474](https://github.com/homarr-labs/homarr/issues/474)) ([82d41ab](https://github.com/homarr-labs/homarr/commit/82d41abf460556ce62f04a700d47208201bdd595)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.2.0 ([#604](https://github.com/homarr-labs/homarr/issues/604)) ([2e044ac](https://github.com/homarr-labs/homarr/commit/2e044ac871fb451160b0619ee430eba3f962c668)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.3.0 ([#694](https://github.com/homarr-labs/homarr/issues/694)) ([4291bde](https://github.com/homarr-labs/homarr/commit/4291bde94f6017c92d44dce50cb795d46f54f9c6)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.4.1 ([#701](https://github.com/homarr-labs/homarr/issues/701)) ([324a643](https://github.com/homarr-labs/homarr/commit/324a643fd1abad4b98bcd14934e4bd23f04e8260)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.4.2 ([#877](https://github.com/homarr-labs/homarr/issues/877)) ([37309e0](https://github.com/homarr-labs/homarr/commit/37309e07279ad46cb3e9e4a29033966d5a34d00a)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.5.0 ([#1130](https://github.com/homarr-labs/homarr/issues/1130)) ([929054d](https://github.com/homarr-labs/homarr/commit/929054d5bddd9863671227c2bc71e07ff4b197be)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.5.1 ([#1177](https://github.com/homarr-labs/homarr/issues/1177)) ([4e431b4](https://github.com/homarr-labs/homarr/commit/4e431b4f8971f18387f84553d1e644980733b383)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.5.2 ([#1181](https://github.com/homarr-labs/homarr/issues/1181)) ([17d6229](https://github.com/homarr-labs/homarr/commit/17d6229a0fadb56f2522256a03e15cca3fb7948e)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.5.3 ([#1194](https://github.com/homarr-labs/homarr/issues/1194)) ([adb59b2](https://github.com/homarr-labs/homarr/commit/adb59b292bd5b6df50c60eac17b2a77d3d28696c)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.6.0 ([#1251](https://github.com/homarr-labs/homarr/issues/1251)) ([9c5ca6f](https://github.com/homarr-labs/homarr/commit/9c5ca6f9069f8b6089212638009d098b3d76298c)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.6.1 ([#1258](https://github.com/homarr-labs/homarr/issues/1258)) ([dea6254](https://github.com/homarr-labs/homarr/commit/dea62547e0f51b6607eef5d278202081e6100509)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.7.0 ([#1273](https://github.com/homarr-labs/homarr/issues/1273)) ([a44ead0](https://github.com/homarr-labs/homarr/commit/a44ead09a39ff3d83d646622f29b4c236d078dc4)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.7.1 ([#1324](https://github.com/homarr-labs/homarr/issues/1324)) ([b1393fa](https://github.com/homarr-labs/homarr/commit/b1393fa59b35d84968fd5d6ecddb29e3c22b4aa3)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.7.2 ([#1339](https://github.com/homarr-labs/homarr/issues/1339)) ([c5cc21a](https://github.com/homarr-labs/homarr/commit/c5cc21a4b0537d2396ba8fe79eaeff0a008a5e75)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.7.3 ([#1417](https://github.com/homarr-labs/homarr/issues/1417)) ([b45eeb9](https://github.com/homarr-labs/homarr/commit/b45eeb95e94b1288bb97b45b1dd6eca3728cde72)) +* **deps:** update dependency @auth/drizzle-adapter to ^1.7.4 ([#1493](https://github.com/homarr-labs/homarr/issues/1493)) ([e9a74a0](https://github.com/homarr-labs/homarr/commit/e9a74a01b900f083143b93c8df73fcaa98009ea0)) +* **deps:** update dependency @auth/drizzle-adapter to v1 ([#359](https://github.com/homarr-labs/homarr/issues/359)) ([ea528ea](https://github.com/homarr-labs/homarr/commit/ea528ea076fec672d7ee57a23ee66244d987f103)) +* **deps:** update dependency @ctrl/deluge to v7 ([#1468](https://github.com/homarr-labs/homarr/issues/1468)) ([70f9dc5](https://github.com/homarr-labs/homarr/commit/70f9dc54606d2518afdd5cef84f6623cfdfa8fd3)) +* **deps:** update dependency @ctrl/qbittorrent to ^9.1.0 ([#1466](https://github.com/homarr-labs/homarr/issues/1466)) ([27931be](https://github.com/homarr-labs/homarr/commit/27931be9825a0ee1a4942abb560127c4e2286aa4)) +* **deps:** update dependency @ctrl/transmission to ^7.1.0 ([#1467](https://github.com/homarr-labs/homarr/issues/1467)) ([f220bb6](https://github.com/homarr-labs/homarr/commit/f220bb62445219f9d010e9a28bcb78789a63d368)) +* **deps:** update dependency @ctrl/transmission to v7 ([#1103](https://github.com/homarr-labs/homarr/issues/1103)) ([5986160](https://github.com/homarr-labs/homarr/commit/59861602652a5717e74a342059cd403151d8a6fd)) +* **deps:** update dependency @dnd-kit/core to ^6.2.0 ([#1534](https://github.com/homarr-labs/homarr/issues/1534)) ([5a3d974](https://github.com/homarr-labs/homarr/commit/5a3d9745d985cccca69f9bbfdf0d0ee922de8cbc)) +* **deps:** update dependency @dnd-kit/core to ^6.3.0 ([#1608](https://github.com/homarr-labs/homarr/issues/1608)) ([6c7cdb3](https://github.com/homarr-labs/homarr/commit/6c7cdb3adb6178888e4e3a5e328433f19803cd29)) +* **deps:** update dependency @dnd-kit/core to ^6.3.1 ([#1613](https://github.com/homarr-labs/homarr/issues/1613)) ([79d52b6](https://github.com/homarr-labs/homarr/commit/79d52b690533973e8ff00a1b4920c3f2cbcd417b)) +* **deps:** update dependency @dnd-kit/sortable to v10 ([#1609](https://github.com/homarr-labs/homarr/issues/1609)) ([1037a74](https://github.com/homarr-labs/homarr/commit/1037a747ea0c6e59fc2efb6562c49d4a3bca7465)) +* **deps:** update dependency @dnd-kit/sortable to v9 ([#1535](https://github.com/homarr-labs/homarr/issues/1535)) ([b68977c](https://github.com/homarr-labs/homarr/commit/b68977c52c84ae9742fd52b554d4838409ab76a6)) +* **deps:** update dependency @drizzle-team/brocli to ^0.10.0 ([#937](https://github.com/homarr-labs/homarr/issues/937)) ([a80b49a](https://github.com/homarr-labs/homarr/commit/a80b49a03e8174a1c4ae7e7abc8c9d32939946b6)) +* **deps:** update dependency @drizzle-team/brocli to ^0.10.1 ([#974](https://github.com/homarr-labs/homarr/issues/974)) ([ba3f173](https://github.com/homarr-labs/homarr/commit/ba3f1739f4be88b84f7c782936fc5c91bfa49fae)) +* **deps:** update dependency @drizzle-team/brocli to ^0.10.2 ([#1380](https://github.com/homarr-labs/homarr/issues/1380)) ([8d2d151](https://github.com/homarr-labs/homarr/commit/8d2d151787b4596e2af79e00345fc1ba40884535)) +* **deps:** update dependency @drizzle-team/brocli to ^0.11.0 ([#1427](https://github.com/homarr-labs/homarr/issues/1427)) ([e332a6f](https://github.com/homarr-labs/homarr/commit/e332a6fcbe719defc29f0ba7ada88fb3434784d9)) +* **deps:** update dependency @homarr/gridstack to v1.0.2 ([#542](https://github.com/homarr-labs/homarr/issues/542)) ([1569862](https://github.com/homarr-labs/homarr/commit/1569862baf77b3a8475c4aacc6f7ae5774be09cd)) +* **deps:** update dependency @ianvs/prettier-plugin-sort-imports to ^4.2.0 ([#227](https://github.com/homarr-labs/homarr/issues/227)) ([179ceae](https://github.com/homarr-labs/homarr/commit/179ceaebf05f53c434e245d1eb7b95a5be3c4d96)) +* **deps:** update dependency @ianvs/prettier-plugin-sort-imports to ^4.2.1 ([#243](https://github.com/homarr-labs/homarr/issues/243)) ([c5428ef](https://github.com/homarr-labs/homarr/commit/c5428efd60fa5217c7191bc3404cac420e9539be)) +* **deps:** update dependency @ianvs/prettier-plugin-sort-imports to ^4.3.0 ([#718](https://github.com/homarr-labs/homarr/issues/718)) ([7a14c25](https://github.com/homarr-labs/homarr/commit/7a14c255be48b9b8e92f7918f6af68a211e2666e)) +* **deps:** update dependency @ianvs/prettier-plugin-sort-imports to ^4.3.1 ([#784](https://github.com/homarr-labs/homarr/issues/784)) ([0a4ff4b](https://github.com/homarr-labs/homarr/commit/0a4ff4b883a40970e4d4b733aa096929ae6ec11a)) +* **deps:** update dependency @ianvs/prettier-plugin-sort-imports to ^4.4.0 ([#1441](https://github.com/homarr-labs/homarr/issues/1441)) ([7cd3156](https://github.com/homarr-labs/homarr/commit/7cd3156bd627b983ebe7eba4ace82535b8a5e913)) +* **deps:** update dependency @jellyfin/sdk to ^0.11.0 ([#1384](https://github.com/homarr-labs/homarr/issues/1384)) ([7a4c9a9](https://github.com/homarr-labs/homarr/commit/7a4c9a9b2e72247577a61285546b0f74f5055d53)) +* **deps:** update dependency @million/lint to v1.0.0 ([#1212](https://github.com/homarr-labs/homarr/issues/1212)) ([b3f6645](https://github.com/homarr-labs/homarr/commit/b3f6645783bc4132480669113dfddac0939c5aeb)) +* **deps:** update dependency @million/lint to v1.0.10 ([#1293](https://github.com/homarr-labs/homarr/issues/1293)) ([ed52b26](https://github.com/homarr-labs/homarr/commit/ed52b26f6d6938d653527af94f341c3b5a69e093)) +* **deps:** update dependency @million/lint to v1.0.11 ([#1294](https://github.com/homarr-labs/homarr/issues/1294)) ([c707b4b](https://github.com/homarr-labs/homarr/commit/c707b4b10ff38e6cf299a503bd8176313d47f3ff)) +* **deps:** update dependency @million/lint to v1.0.12 ([#1459](https://github.com/homarr-labs/homarr/issues/1459)) ([ce32b48](https://github.com/homarr-labs/homarr/commit/ce32b4839d5074a38922c8bff389524d3e4619f4)) +* **deps:** update dependency @million/lint to v1.0.13 ([#1557](https://github.com/homarr-labs/homarr/issues/1557)) ([f2268c8](https://github.com/homarr-labs/homarr/commit/f2268c8041955c39206b1b8373278f170f76eae0)) +* **deps:** update dependency @million/lint to v1.0.14 ([#1647](https://github.com/homarr-labs/homarr/issues/1647)) ([4c7058b](https://github.com/homarr-labs/homarr/commit/4c7058b159858f3873aaf5dd95d5581696b3f30f)) +* **deps:** update dependency @million/lint to v1.0.7 ([#1225](https://github.com/homarr-labs/homarr/issues/1225)) ([770a0d6](https://github.com/homarr-labs/homarr/commit/770a0d63f9bab2f06e859bebe525ab9b222a5351)) +* **deps:** update dependency @million/lint to v1.0.8 ([#1231](https://github.com/homarr-labs/homarr/issues/1231)) ([547287d](https://github.com/homarr-labs/homarr/commit/547287dba1d37858f5406011bcbed20cbce08c9a)) +* **deps:** update dependency @million/lint to v1.0.9 ([#1255](https://github.com/homarr-labs/homarr/issues/1255)) ([1d281c0](https://github.com/homarr-labs/homarr/commit/1d281c0cc947612b21f65a1beca41e37a81403b0)) +* **deps:** update dependency @t3-oss/env-nextjs to ^0.10.1 ([#375](https://github.com/homarr-labs/homarr/issues/375)) ([73a72dc](https://github.com/homarr-labs/homarr/commit/73a72dc6755ee39fb1282ddde347a84d6aa8419f)) +* **deps:** update dependency @t3-oss/env-nextjs to ^0.11.0 ([#851](https://github.com/homarr-labs/homarr/issues/851)) ([88e5ac2](https://github.com/homarr-labs/homarr/commit/88e5ac2f71ed21e9a99969210b293e51d34b5106)) +* **deps:** update dependency @t3-oss/env-nextjs to ^0.11.1 ([#1029](https://github.com/homarr-labs/homarr/issues/1029)) ([e193c1c](https://github.com/homarr-labs/homarr/commit/e193c1c6f52c3a3e0072262227af82481d71b088)) +* **deps:** update dependency @t3-oss/env-nextjs to ^0.8.0 ([#31](https://github.com/homarr-labs/homarr/issues/31)) ([f8a3aae](https://github.com/homarr-labs/homarr/commit/f8a3aae1163d1b5d645e7e9fe0228846a856d4e6)) +* **deps:** update dependency @t3-oss/env-nextjs to ^0.9.2 ([#69](https://github.com/homarr-labs/homarr/issues/69)) ([11d1568](https://github.com/homarr-labs/homarr/commit/11d15687149f2bf55aba1999f368436b15b4a9ce)) +* **deps:** update dependency @tabler/icons-react to ^2.47.0 ([#32](https://github.com/homarr-labs/homarr/issues/32)) ([6a892e0](https://github.com/homarr-labs/homarr/commit/6a892e02c8aadcbfb192a65b56543ee27a3dc966)) +* **deps:** update dependency @tabler/icons-react to ^3.0.3 ([#229](https://github.com/homarr-labs/homarr/issues/229)) ([64354e4](https://github.com/homarr-labs/homarr/commit/64354e4b43ce4c7e9e2f1c816e2af8e3c15d905b)) +* **deps:** update dependency @tabler/icons-react to ^3.1.0 ([#236](https://github.com/homarr-labs/homarr/issues/236)) ([333aaf3](https://github.com/homarr-labs/homarr/commit/333aaf34dc85d24b9f7cf6451d65f566369ffa21)) +* **deps:** update dependency @tabler/icons-react to ^3.10.0 ([#769](https://github.com/homarr-labs/homarr/issues/769)) ([bf70143](https://github.com/homarr-labs/homarr/commit/bf70143ccab2ef6a35d739279af91c51e0be72e4)) +* **deps:** update dependency @tabler/icons-react to ^3.11.0 ([#818](https://github.com/homarr-labs/homarr/issues/818)) ([30669d2](https://github.com/homarr-labs/homarr/commit/30669d23e32974cbea3881fe2a0712985f59394d)) +* **deps:** update dependency @tabler/icons-react to ^3.12.0 ([#944](https://github.com/homarr-labs/homarr/issues/944)) ([21c0e4b](https://github.com/homarr-labs/homarr/commit/21c0e4b35471071cd73472a116f42550a4b7a509)) +* **deps:** update dependency @tabler/icons-react to ^3.13.0 ([#1034](https://github.com/homarr-labs/homarr/issues/1034)) ([2ea0d04](https://github.com/homarr-labs/homarr/commit/2ea0d04c71087bf56fd85c36955ba62ccf78e94b)) +* **deps:** update dependency @tabler/icons-react to ^3.14.0 ([#1039](https://github.com/homarr-labs/homarr/issues/1039)) ([961fca0](https://github.com/homarr-labs/homarr/commit/961fca0f647e569ee87a787d58e36c3c5f4fdedb)) +* **deps:** update dependency @tabler/icons-react to ^3.15.0 ([#1085](https://github.com/homarr-labs/homarr/issues/1085)) ([7b6301e](https://github.com/homarr-labs/homarr/commit/7b6301e498d608099f462b30177e8067bb0647b3)) +* **deps:** update dependency @tabler/icons-react to ^3.16.0 ([#1096](https://github.com/homarr-labs/homarr/issues/1096)) ([18c1da4](https://github.com/homarr-labs/homarr/commit/18c1da4a6296aadda9e9ecd88f112c1302b3e3ee)) +* **deps:** update dependency @tabler/icons-react to ^3.17.0 ([#1126](https://github.com/homarr-labs/homarr/issues/1126)) ([6685f4c](https://github.com/homarr-labs/homarr/commit/6685f4c8060867ec32e28c8ddfa351791feeaa53)) +* **deps:** update dependency @tabler/icons-react to ^3.18.0 ([#1188](https://github.com/homarr-labs/homarr/issues/1188)) ([1bce7a3](https://github.com/homarr-labs/homarr/commit/1bce7a300d616ad05dcf191a859af2bb665a41dd)) +* **deps:** update dependency @tabler/icons-react to ^3.19.0 ([#1197](https://github.com/homarr-labs/homarr/issues/1197)) ([8aaa4f5](https://github.com/homarr-labs/homarr/commit/8aaa4f5856ccac86ddd0e1e5ce3fc0178fda9597)) +* **deps:** update dependency @tabler/icons-react to ^3.2.0 ([#342](https://github.com/homarr-labs/homarr/issues/342)) ([c40533e](https://github.com/homarr-labs/homarr/commit/c40533e758ee60709a42b54e41345583cab40e51)) +* **deps:** update dependency @tabler/icons-react to ^3.20.0 ([#1359](https://github.com/homarr-labs/homarr/issues/1359)) ([30d4464](https://github.com/homarr-labs/homarr/commit/30d4464067583632bd9549b703dd886cac61a3f2)) +* **deps:** update dependency @tabler/icons-react to ^3.21.0 ([#1382](https://github.com/homarr-labs/homarr/issues/1382)) ([958c62c](https://github.com/homarr-labs/homarr/commit/958c62c92689ccdb466f7760dd053ca5f51099dc)) +* **deps:** update dependency @tabler/icons-react to ^3.22.0 ([#1471](https://github.com/homarr-labs/homarr/issues/1471)) ([a1fddaa](https://github.com/homarr-labs/homarr/commit/a1fddaa6a61fdcbc892e704bea8a0a0b73ab1e1e)) +* **deps:** update dependency @tabler/icons-react to ^3.23.0 ([#1566](https://github.com/homarr-labs/homarr/issues/1566)) ([fd42bde](https://github.com/homarr-labs/homarr/commit/fd42bde76ddf46f51f787cab832636f33187b006)) +* **deps:** update dependency @tabler/icons-react to ^3.24.0 ([#1587](https://github.com/homarr-labs/homarr/issues/1587)) ([23cc465](https://github.com/homarr-labs/homarr/commit/23cc4659c4cd14e7f95253e56fddd3a010d908c1)) +* **deps:** update dependency @tabler/icons-react to ^3.26.0 ([#1667](https://github.com/homarr-labs/homarr/issues/1667)) ([8c596bf](https://github.com/homarr-labs/homarr/commit/8c596bf5fa9119bd22375f2fc8408ebac8eb0bcb)) +* **deps:** update dependency @tabler/icons-react to ^3.3.0 ([#405](https://github.com/homarr-labs/homarr/issues/405)) ([46bb3ee](https://github.com/homarr-labs/homarr/commit/46bb3ee0c98f1a0c24ef1111d5ffd86b0446c9f1)) +* **deps:** update dependency @tabler/icons-react to ^3.4.0 ([#501](https://github.com/homarr-labs/homarr/issues/501)) ([3fe1a19](https://github.com/homarr-labs/homarr/commit/3fe1a19e378810c86f4526d218758becd71bbe9f)) +* **deps:** update dependency @tabler/icons-react to ^3.5.0 ([#532](https://github.com/homarr-labs/homarr/issues/532)) ([63f7431](https://github.com/homarr-labs/homarr/commit/63f743175edbc2d46c6eb0cb7f7a41e8007cd038)) +* **deps:** update dependency @tabler/icons-react to ^3.6.0 ([#664](https://github.com/homarr-labs/homarr/issues/664)) ([e4c6864](https://github.com/homarr-labs/homarr/commit/e4c6864a94fc0dc0449249043b2cf8037783c99f)) +* **deps:** update dependency @tabler/icons-react to ^3.7.0 ([#715](https://github.com/homarr-labs/homarr/issues/715)) ([6a3a846](https://github.com/homarr-labs/homarr/commit/6a3a8465e701aa4449d9993151ebace0f71542b2)) +* **deps:** update dependency @tabler/icons-react to ^3.8.0 ([#737](https://github.com/homarr-labs/homarr/issues/737)) ([e12531c](https://github.com/homarr-labs/homarr/commit/e12531ccccfdfafd21c6cb62533b1c4752a13e80)) +* **deps:** update dependency @tabler/icons-react to ^3.9.0 ([#745](https://github.com/homarr-labs/homarr/issues/745)) ([75e5a6c](https://github.com/homarr-labs/homarr/commit/75e5a6c42ff41b72b1d86fcac61f7d8c89ac337d)) +* **deps:** update dependency @tabler/icons-react to v3 ([#215](https://github.com/homarr-labs/homarr/issues/215)) ([1c222ed](https://github.com/homarr-labs/homarr/commit/1c222ed89cd53dccc41445631f777424705a444a)) +* **deps:** update dependency @tanstack/react-query-devtools to ^5.21.0 ([#101](https://github.com/homarr-labs/homarr/issues/101)) ([4ea1d14](https://github.com/homarr-labs/homarr/commit/4ea1d14966aebf7477fdfebce0e1bf3833ac70c2)) +* **deps:** update dependency @tanstack/react-query-devtools to ^5.21.5 ([#130](https://github.com/homarr-labs/homarr/issues/130)) ([dbf02c6](https://github.com/homarr-labs/homarr/commit/dbf02c62641e541682a39ebd5bba4a4cc87d94ab)) +* **deps:** update dependency @tanstack/react-query-devtools to ^5.54.0 ([#1060](https://github.com/homarr-labs/homarr/issues/1060)) ([6ea4a74](https://github.com/homarr-labs/homarr/commit/6ea4a74675b271573e25fb88d8ecd62f9f83be12)) +* **deps:** update dependency @tanstack/react-query-devtools to ^5.58.0 ([#1175](https://github.com/homarr-labs/homarr/issues/1175)) ([e2414f5](https://github.com/homarr-labs/homarr/commit/e2414f5e9f6cca92e43a7c8e551cd84d73925db6)) +* **deps:** update dependency @tanstack/react-query-next-experimental to v5.41.0 ([#639](https://github.com/homarr-labs/homarr/issues/639)) ([38c32cb](https://github.com/homarr-labs/homarr/commit/38c32cbece6e400482d1fd69c7b6bcf971224848)) +* **deps:** update dependency @tanstack/react-query-next-experimental to v5.46.0 ([#699](https://github.com/homarr-labs/homarr/issues/699)) ([8d7a7bc](https://github.com/homarr-labs/homarr/commit/8d7a7bc9b1d8051be6a879cecb405934e508fc21)) +* **deps:** update dependency @trpc/client to v11.0.0-next-beta.318 ([#234](https://github.com/homarr-labs/homarr/issues/234)) ([ab55a13](https://github.com/homarr-labs/homarr/commit/ab55a1357dec7bbd8b9ce68d635f89078954d091)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.330 ([#288](https://github.com/homarr-labs/homarr/issues/288)) ([d8d25d5](https://github.com/homarr-labs/homarr/commit/d8d25d50379aa4b4514e61418a8bdf0430063256)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.332 ([#308](https://github.com/homarr-labs/homarr/issues/308)) ([50c1624](https://github.com/homarr-labs/homarr/commit/50c162444c45c954755fcca22bed6e3d1443f950)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.334 ([#334](https://github.com/homarr-labs/homarr/issues/334)) ([ed5e5d1](https://github.com/homarr-labs/homarr/commit/ed5e5d1edcbd5d0d8cefa9664ebe0f3d08ae1499)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.345 ([#351](https://github.com/homarr-labs/homarr/issues/351)) ([0ba6455](https://github.com/homarr-labs/homarr/commit/0ba64559829f2257d3ce59493e9ed9d012f88bce)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.354 ([#368](https://github.com/homarr-labs/homarr/issues/368)) ([d88b6de](https://github.com/homarr-labs/homarr/commit/d88b6def759bf8a4980aa67e7fa652be7def8c95)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.359 ([#394](https://github.com/homarr-labs/homarr/issues/394)) ([47accae](https://github.com/homarr-labs/homarr/commit/47accae90d7d56c5aa1ea33d74350addd2038a10)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.361 ([#404](https://github.com/homarr-labs/homarr/issues/404)) ([6dff7c4](https://github.com/homarr-labs/homarr/commit/6dff7c48e2622a1e0df1c3f8ab86450a0899d395)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.362 ([#407](https://github.com/homarr-labs/homarr/issues/407)) ([0020680](https://github.com/homarr-labs/homarr/commit/0020680ca097b82ade46fc7e82c83d0da60d6e1c)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.364 ([#409](https://github.com/homarr-labs/homarr/issues/409)) ([7bc7bd6](https://github.com/homarr-labs/homarr/commit/7bc7bd6bf9dbdeaeb6b62d35cb7fb3db6074245f)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.366 ([#454](https://github.com/homarr-labs/homarr/issues/454)) ([1172d84](https://github.com/homarr-labs/homarr/commit/1172d842235cf8e01279dc2ee44360b0773b3b20)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.373 ([#493](https://github.com/homarr-labs/homarr/issues/493)) ([1abf441](https://github.com/homarr-labs/homarr/commit/1abf441cdba8a8f3a32600c197d1e414fb41f655)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.374 ([#522](https://github.com/homarr-labs/homarr/issues/522)) ([eb0db3e](https://github.com/homarr-labs/homarr/commit/eb0db3ec4efc7d07bdb24dac6299d61b3164f666)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.377 ([#553](https://github.com/homarr-labs/homarr/issues/553)) ([abdf9bc](https://github.com/homarr-labs/homarr/commit/abdf9bc122cddb7b97ec48a8aacca27b382c02a3)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.382 ([#568](https://github.com/homarr-labs/homarr/issues/568)) ([e448eeb](https://github.com/homarr-labs/homarr/commit/e448eeb0a62a91aeab31547055cc7b94b5de9bcb)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.383 ([#608](https://github.com/homarr-labs/homarr/issues/608)) ([869efbc](https://github.com/homarr-labs/homarr/commit/869efbc6388bcd48b49d6f2b27f7e2609855ceab)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.390 ([#609](https://github.com/homarr-labs/homarr/issues/609)) ([812b8d8](https://github.com/homarr-labs/homarr/commit/812b8d8306672b99d2bfe5f0284bc92a585f8284)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.394 ([#626](https://github.com/homarr-labs/homarr/issues/626)) ([5bf1ddd](https://github.com/homarr-labs/homarr/commit/5bf1ddde4b509373a641f29c480b60598ada7bd9)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.396 ([#634](https://github.com/homarr-labs/homarr/issues/634)) ([475f472](https://github.com/homarr-labs/homarr/commit/475f472cb0885bf70133e08f3bde08830476ce39)) +* **deps:** update dependency @trpc/client to v11.0.0-rc.401 ([#648](https://github.com/homarr-labs/homarr/issues/648)) ([84851db](https://github.com/homarr-labs/homarr/commit/84851db333a08ecc7d7255e0a2300e45d50a446b)) +* **deps:** update dependency @typescript-eslint/eslint-plugin to ^7.4.0 ([#271](https://github.com/homarr-labs/homarr/issues/271)) ([dd7f04e](https://github.com/homarr-labs/homarr/commit/dd7f04e3955644dcac7acf4446b454aaaa7ee387)) +* **deps:** update dependency @typescript-eslint/parser to ^7.4.0 ([#270](https://github.com/homarr-labs/homarr/issues/270)) ([c4a4452](https://github.com/homarr-labs/homarr/commit/c4a445283901128a738af553f54a912a48661f1d)) +* **deps:** update dependency @umami/node to ^0.4.0 ([#1000](https://github.com/homarr-labs/homarr/issues/1000)) ([72aed22](https://github.com/homarr-labs/homarr/commit/72aed221254b3bcfdaad3f26b2984ddbf7e4e152)) +* **deps:** update dependency better-sqlite3 to ^10.1.0 ([#584](https://github.com/homarr-labs/homarr/issues/584)) ([6d46e91](https://github.com/homarr-labs/homarr/commit/6d46e91a7cbbe6a892453c040da8b7b841d9ad2c)) +* **deps:** update dependency better-sqlite3 to ^11.1.1 ([#720](https://github.com/homarr-labs/homarr/issues/720)) ([c8d4461](https://github.com/homarr-labs/homarr/commit/c8d4461ab82b57c4719fcc805d75caac7db381ee)) +* **deps:** update dependency better-sqlite3 to ^11.1.2 ([#736](https://github.com/homarr-labs/homarr/issues/736)) ([6aecd1a](https://github.com/homarr-labs/homarr/commit/6aecd1a713575374b49253e074e4c1d52db58b77)) +* **deps:** update dependency better-sqlite3 to ^11.2.0 ([#1004](https://github.com/homarr-labs/homarr/issues/1004)) ([4e6437a](https://github.com/homarr-labs/homarr/commit/4e6437a180e3c25e6265803f2179d9caf119b64d)) +* **deps:** update dependency better-sqlite3 to ^11.2.1 ([#1006](https://github.com/homarr-labs/homarr/issues/1006)) ([051d57b](https://github.com/homarr-labs/homarr/commit/051d57bb399cea562f89b52a179d77c6bc90a3fc)) +* **deps:** update dependency better-sqlite3 to ^11.3.0 ([#1092](https://github.com/homarr-labs/homarr/issues/1092)) ([ed0c613](https://github.com/homarr-labs/homarr/commit/ed0c6136e61c46a9b90c5bbd1a85abbf4dfb68f5)) +* **deps:** update dependency better-sqlite3 to ^11.4.0 ([#1320](https://github.com/homarr-labs/homarr/issues/1320)) ([601af7a](https://github.com/homarr-labs/homarr/commit/601af7acd811a822a7d61d03094a61192e6947ed)) +* **deps:** update dependency better-sqlite3 to ^11.5.0 ([#1350](https://github.com/homarr-labs/homarr/issues/1350)) ([d599390](https://github.com/homarr-labs/homarr/commit/d599390512a169e15a4f9a1bff5f45eaf2e18834)) +* **deps:** update dependency better-sqlite3 to ^11.6.0 ([#1548](https://github.com/homarr-labs/homarr/issues/1548)) ([93aedd9](https://github.com/homarr-labs/homarr/commit/93aedd994f405a1e60913086900015c94a364962)) +* **deps:** update dependency better-sqlite3 to ^11.7.0 ([#1628](https://github.com/homarr-labs/homarr/issues/1628)) ([753e0ec](https://github.com/homarr-labs/homarr/commit/753e0ecad2f57ca1fa2202a9678ea7c2f1e67c5b)) +* **deps:** update dependency better-sqlite3 to ^9.4.0 ([#33](https://github.com/homarr-labs/homarr/issues/33)) ([00db901](https://github.com/homarr-labs/homarr/commit/00db9018339ae31f07edcd89a023f569aec0dbe5)) +* **deps:** update dependency better-sqlite3 to ^9.4.1 ([#83](https://github.com/homarr-labs/homarr/issues/83)) ([34f06e8](https://github.com/homarr-labs/homarr/commit/34f06e817db014e101e16543cdfc518485990a0d)) +* **deps:** update dependency better-sqlite3 to ^9.4.3 ([#118](https://github.com/homarr-labs/homarr/issues/118)) ([baa541a](https://github.com/homarr-labs/homarr/commit/baa541afa9c2f91bd56ec99bb24fc6cdb585991b)) +* **deps:** update dependency better-sqlite3 to ^9.4.5 ([#302](https://github.com/homarr-labs/homarr/issues/302)) ([7bff8e5](https://github.com/homarr-labs/homarr/commit/7bff8e5148875b72a5218e6856d10249f435b53b)) +* **deps:** update dependency better-sqlite3 to ^9.5.0 ([#335](https://github.com/homarr-labs/homarr/issues/335)) ([48a4b8b](https://github.com/homarr-labs/homarr/commit/48a4b8ba7e6b535fd1828713a0c4fadcbff89ec8)) +* **deps:** update dependency better-sqlite3 to ^9.6.0 ([#386](https://github.com/homarr-labs/homarr/issues/386)) ([45ffbad](https://github.com/homarr-labs/homarr/commit/45ffbadeece8a82dcb1e202e5934335a5d2d8832)) +* **deps:** update dependency better-sqlite3 to v10 ([#479](https://github.com/homarr-labs/homarr/issues/479)) ([f0da1d8](https://github.com/homarr-labs/homarr/commit/f0da1d81a6cd8b425919ffb9460b5f6bbb82ae2a)) +* **deps:** update dependency better-sqlite3 to v11 ([#587](https://github.com/homarr-labs/homarr/issues/587)) ([96150f8](https://github.com/homarr-labs/homarr/commit/96150f802d1c75ed6a10bf05a5f19c259ead581b)) +* **deps:** update dependency chroma-js to ^2.5.0 ([#890](https://github.com/homarr-labs/homarr/issues/890)) ([79cabe6](https://github.com/homarr-labs/homarr/commit/79cabe65801de1c180691f3413ef01939ede14be)) +* **deps:** update dependency chroma-js to ^2.6.0 ([#891](https://github.com/homarr-labs/homarr/issues/891)) ([15171dd](https://github.com/homarr-labs/homarr/commit/15171dd5afd12cbdc459442d2cab0164128381cb)) +* **deps:** update dependency chroma-js to ^3.1.0 ([#1081](https://github.com/homarr-labs/homarr/issues/1081)) ([4f42143](https://github.com/homarr-labs/homarr/commit/4f421433c2fa3918771f9138e45c3b526a6a9396)) +* **deps:** update dependency chroma-js to ^3.1.1 ([#1082](https://github.com/homarr-labs/homarr/issues/1082)) ([6bf0a53](https://github.com/homarr-labs/homarr/commit/6bf0a53d21a47542cceeec93eb90828206f2e81d)) +* **deps:** update dependency chroma-js to ^3.1.2 ([#1289](https://github.com/homarr-labs/homarr/issues/1289)) ([1bc470a](https://github.com/homarr-labs/homarr/commit/1bc470a39feae570a76dc210946ffc18b9bef6ea)) +* **deps:** update dependency chroma-js to v3 ([#992](https://github.com/homarr-labs/homarr/issues/992)) ([3eb9096](https://github.com/homarr-labs/homarr/commit/3eb90968ac8e5de059b3e14c0736433b005f5409)) +* **deps:** update dependency dayjs to ^1.11.11 ([#393](https://github.com/homarr-labs/homarr/issues/393)) ([03c2993](https://github.com/homarr-labs/homarr/commit/03c2993611e992cb24a142f050bdcd763c7813e2)) +* **deps:** update dependency dayjs to ^1.11.12 ([#832](https://github.com/homarr-labs/homarr/issues/832)) ([5c92f6a](https://github.com/homarr-labs/homarr/commit/5c92f6a3cc1febf9d96e394f54d2f5f94d9ab52e)) +* **deps:** update dependency dayjs to ^1.11.13 ([#1001](https://github.com/homarr-labs/homarr/issues/1001)) ([27d08ba](https://github.com/homarr-labs/homarr/commit/27d08baa2d6f82f521dc46a359ce3d24f1ac857a)) +* **deps:** update dependency dotenv to ^16.4.6 ([#1588](https://github.com/homarr-labs/homarr/issues/1588)) ([716a2ab](https://github.com/homarr-labs/homarr/commit/716a2ab9d1f949748a39858daa330e9df32597fa)) +* **deps:** update dependency dotenv to ^16.4.7 ([#1597](https://github.com/homarr-labs/homarr/issues/1597)) ([31cc1ab](https://github.com/homarr-labs/homarr/commit/31cc1abb51c8867f8f9934815f24de5e190f3142)) +* **deps:** update dependency drizzle-kit to ^0.20.16 ([#362](https://github.com/homarr-labs/homarr/issues/362)) ([f58d0dd](https://github.com/homarr-labs/homarr/commit/f58d0ddd94633468872ccd93f908e39f0ccc9337)) +* **deps:** update dependency drizzle-kit to ^0.20.17 ([#367](https://github.com/homarr-labs/homarr/issues/367)) ([04a3131](https://github.com/homarr-labs/homarr/commit/04a313186f63c4810fdc4f062a94aedf77bf526b)) +* **deps:** update dependency drizzle-kit to ^0.20.18 ([#449](https://github.com/homarr-labs/homarr/issues/449)) ([5eb1d71](https://github.com/homarr-labs/homarr/commit/5eb1d716ded4fb1529e35afa0741646874b74a43)) +* **deps:** update dependency drizzle-kit to ^0.21.1 ([#462](https://github.com/homarr-labs/homarr/issues/462)) ([1ce6fb0](https://github.com/homarr-labs/homarr/commit/1ce6fb0d0fd3f2770ea2a2f3dec7104b03e2e4ff)) +* **deps:** update dependency drizzle-kit to ^0.21.2 ([#495](https://github.com/homarr-labs/homarr/issues/495)) ([8166fdb](https://github.com/homarr-labs/homarr/commit/8166fdb8e22842125933e93325c27fd561f5df02)) +* **deps:** update dependency drizzle-kit to ^0.21.4 ([#535](https://github.com/homarr-labs/homarr/issues/535)) ([56b6d76](https://github.com/homarr-labs/homarr/commit/56b6d76f43e7cfaac080d029a68a55eb243970e7)) +* **deps:** update dependency drizzle-kit to ^0.22.0 ([#588](https://github.com/homarr-labs/homarr/issues/588)) ([d16281b](https://github.com/homarr-labs/homarr/commit/d16281bea7f71bb6ed3292bc47ed3b2d0103e814)) +* **deps:** update dependency drizzle-kit to ^0.22.1 ([#590](https://github.com/homarr-labs/homarr/issues/590)) ([51fb7cb](https://github.com/homarr-labs/homarr/commit/51fb7cb402e45ee9f9bebbc153ec1f37fc4d4158)) +* **deps:** update dependency drizzle-kit to ^0.22.2 ([#618](https://github.com/homarr-labs/homarr/issues/618)) ([f5aaf89](https://github.com/homarr-labs/homarr/commit/f5aaf89a3db6e10f2ac07d3ac29300ec81575e61)) +* **deps:** update dependency drizzle-kit to ^0.22.4 ([#625](https://github.com/homarr-labs/homarr/issues/625)) ([dda34e7](https://github.com/homarr-labs/homarr/commit/dda34e7764ace4f20ec9742289987dc43ee2573c)) +* **deps:** update dependency drizzle-kit to ^0.22.5 ([#631](https://github.com/homarr-labs/homarr/issues/631)) ([2462726](https://github.com/homarr-labs/homarr/commit/246272669e2cef242a7ddda2d6bbafe5313ca3ec)) +* **deps:** update dependency drizzle-kit to ^0.22.6 ([#636](https://github.com/homarr-labs/homarr/issues/636)) ([66ddb45](https://github.com/homarr-labs/homarr/commit/66ddb4597530479eac3d1e417d1fabac39ad6d8c)) +* **deps:** update dependency drizzle-kit to ^0.22.7 ([#652](https://github.com/homarr-labs/homarr/issues/652)) ([d985fbe](https://github.com/homarr-labs/homarr/commit/d985fbe69a0c1f57d574bd547567a3cd486174b4)) +* **deps:** update dependency drizzle-kit to ^0.22.8 ([#729](https://github.com/homarr-labs/homarr/issues/729)) ([be100b6](https://github.com/homarr-labs/homarr/commit/be100b610eabb3acbbbe0827dc07e012962c8ad8)) +* **deps:** update dependency drizzle-kit to ^0.23.0 ([#775](https://github.com/homarr-labs/homarr/issues/775)) ([f2c70a4](https://github.com/homarr-labs/homarr/commit/f2c70a4d0b6b827b54a7b12f53c01b1094548c2e)) +* **deps:** update dependency drizzle-kit to ^0.23.1 ([#888](https://github.com/homarr-labs/homarr/issues/888)) ([5f89d93](https://github.com/homarr-labs/homarr/commit/5f89d93db64c5033053da239b6e94c2731958924)) +* **deps:** update dependency drizzle-kit to ^0.23.2 ([#918](https://github.com/homarr-labs/homarr/issues/918)) ([d378ddb](https://github.com/homarr-labs/homarr/commit/d378ddb42bd43971d88b43cb90e24d83d69d9812)) +* **deps:** update dependency drizzle-kit to ^0.24.0 ([#939](https://github.com/homarr-labs/homarr/issues/939)) ([940a489](https://github.com/homarr-labs/homarr/commit/940a4890e26a0c080fb084e6026c0438d9df6914)) +* **deps:** update dependency drizzle-kit to ^0.24.1 ([#1012](https://github.com/homarr-labs/homarr/issues/1012)) ([cd0af7e](https://github.com/homarr-labs/homarr/commit/cd0af7e8f18d0e1b21f28bafd12aaf8bb06009c9)) +* **deps:** update dependency drizzle-kit to ^0.24.2 ([#1033](https://github.com/homarr-labs/homarr/issues/1033)) ([78b45c4](https://github.com/homarr-labs/homarr/commit/78b45c4a5bae9839990b12127fda9c7e15d07b25)) +* **deps:** update dependency drizzle-kit to ^0.25.0 ([#1261](https://github.com/homarr-labs/homarr/issues/1261)) ([635fadf](https://github.com/homarr-labs/homarr/commit/635fadfce9842f6e8bdc2e4757256e8bd27ae868)) +* **deps:** update dependency drizzle-kit to ^0.26.0 ([#1301](https://github.com/homarr-labs/homarr/issues/1301)) ([f2f31b5](https://github.com/homarr-labs/homarr/commit/f2f31b5ee08f1c50ccc125e0ace470c360984350)) +* **deps:** update dependency drizzle-kit to ^0.26.1 ([#1303](https://github.com/homarr-labs/homarr/issues/1303)) ([f50f46d](https://github.com/homarr-labs/homarr/commit/f50f46d4b7b32bbd89073433316f461cd475e367)) +* **deps:** update dependency drizzle-kit to ^0.26.2 ([#1305](https://github.com/homarr-labs/homarr/issues/1305)) ([da13d63](https://github.com/homarr-labs/homarr/commit/da13d6396967419466729b4abd5a839b14a17977)) +* **deps:** update dependency drizzle-kit to ^0.27.0 ([#1389](https://github.com/homarr-labs/homarr/issues/1389)) ([d3f9696](https://github.com/homarr-labs/homarr/commit/d3f9696127d21d75c16b52ed5a661909db54f705)) +* **deps:** update dependency drizzle-kit to ^0.27.1 ([#1395](https://github.com/homarr-labs/homarr/issues/1395)) ([3bfdc2d](https://github.com/homarr-labs/homarr/commit/3bfdc2ded499a465ce5cb078adc83ee71377bb5e)) +* **deps:** update dependency drizzle-kit to ^0.27.2 ([#1437](https://github.com/homarr-labs/homarr/issues/1437)) ([10cebff](https://github.com/homarr-labs/homarr/commit/10cebff4edb1ad9ff61f1a0ff27b6f360db7e05f)) +* **deps:** update dependency drizzle-kit to ^0.28.0 ([#1439](https://github.com/homarr-labs/homarr/issues/1439)) ([c6a1aee](https://github.com/homarr-labs/homarr/commit/c6a1aeef4d2e2939e262912eaa10018b5c1c4d60)) +* **deps:** update dependency drizzle-kit to ^0.28.1 ([#1480](https://github.com/homarr-labs/homarr/issues/1480)) ([acc440b](https://github.com/homarr-labs/homarr/commit/acc440bb8975fee8ce37e9290fbd4b993b6fddc6)) +* **deps:** update dependency drizzle-kit to ^0.29.0 ([#1591](https://github.com/homarr-labs/homarr/issues/1591)) ([a8e045b](https://github.com/homarr-labs/homarr/commit/a8e045b2239202d469c802b00cc4e4528932b8ee)) +* **deps:** update dependency drizzle-kit to ^0.29.1 ([#1603](https://github.com/homarr-labs/homarr/issues/1603)) ([2e23b3d](https://github.com/homarr-labs/homarr/commit/2e23b3dad84ff3eaa57ec26805b75fb271e12027)) +* **deps:** update dependency drizzle-kit to ^0.30.0 ([#1630](https://github.com/homarr-labs/homarr/issues/1630)) ([46ce061](https://github.com/homarr-labs/homarr/commit/46ce06155b4df45f3676998a813f3a7cecdba085)) +* **deps:** update dependency drizzle-kit to ^0.30.1 ([#1651](https://github.com/homarr-labs/homarr/issues/1651)) ([6418dfe](https://github.com/homarr-labs/homarr/commit/6418dfed382c88cdfe3ea0078ee18c5ae04ec721)) +* **deps:** update dependency drizzle-orm to ^0.29.4 ([#150](https://github.com/homarr-labs/homarr/issues/150)) ([4cf505f](https://github.com/homarr-labs/homarr/commit/4cf505f0c50faa74e699a29fd98eab88b20c14e1)) +* **deps:** update dependency drizzle-orm to ^0.29.5 ([#203](https://github.com/homarr-labs/homarr/issues/203)) ([4f41765](https://github.com/homarr-labs/homarr/commit/4f41765f1039daa2dcd8e9e0e26b3569539697f7)) +* **deps:** update dependency drizzle-orm to ^0.30.1 ([#210](https://github.com/homarr-labs/homarr/issues/210)) ([e34161f](https://github.com/homarr-labs/homarr/commit/e34161f33ecc7c58df4c26f383cf827fd663884b)) +* **deps:** update dependency drizzle-orm to ^0.30.10 ([#413](https://github.com/homarr-labs/homarr/issues/413)) ([14d941e](https://github.com/homarr-labs/homarr/commit/14d941e57ad70573954b276816d28e7d341df673)) +* **deps:** update dependency drizzle-orm to ^0.30.2 ([#232](https://github.com/homarr-labs/homarr/issues/232)) ([9046517](https://github.com/homarr-labs/homarr/commit/90465175f9cec9f95e14541e5c94e5eeadfc90a6)) +* **deps:** update dependency drizzle-orm to ^0.30.4 ([#250](https://github.com/homarr-labs/homarr/issues/250)) ([cdc4870](https://github.com/homarr-labs/homarr/commit/cdc4870925944317ff7f5f7ad8fee80433cd4e05)) +* **deps:** update dependency drizzle-orm to ^0.30.6 ([#282](https://github.com/homarr-labs/homarr/issues/282)) ([6ef58be](https://github.com/homarr-labs/homarr/commit/6ef58beead0137128cefe65d8119317572304b35)) +* **deps:** update dependency drizzle-orm to ^0.30.7 ([#303](https://github.com/homarr-labs/homarr/issues/303)) ([362257c](https://github.com/homarr-labs/homarr/commit/362257cf2b6b60027485f59df080bcdb83c3a85e)) +* **deps:** update dependency drizzle-orm to ^0.30.8 ([#339](https://github.com/homarr-labs/homarr/issues/339)) ([f50550b](https://github.com/homarr-labs/homarr/commit/f50550b3e135375e44b77ddc958f8ba3cf17d214)) +* **deps:** update dependency drizzle-orm to ^0.30.9 ([#370](https://github.com/homarr-labs/homarr/issues/370)) ([f5002c3](https://github.com/homarr-labs/homarr/commit/f5002c3265a9318770d9e6d41aa3583e84fc40d9)) +* **deps:** update dependency drizzle-orm to ^0.31.0 ([#589](https://github.com/homarr-labs/homarr/issues/589)) ([3b39e87](https://github.com/homarr-labs/homarr/commit/3b39e87212acedb8904584a3b3d55fbfd1434fd3)) +* **deps:** update dependency drizzle-orm to ^0.31.1 ([#619](https://github.com/homarr-labs/homarr/issues/619)) ([710197b](https://github.com/homarr-labs/homarr/commit/710197b3a02e06be6a60df71a180fd31b913858a)) +* **deps:** update dependency drizzle-orm to ^0.31.2 ([#632](https://github.com/homarr-labs/homarr/issues/632)) ([efd958d](https://github.com/homarr-labs/homarr/commit/efd958d6cbf5ec5dd0951ca33e87489aa5ec5c16)) +* **deps:** update dependency drizzle-orm to ^0.31.3 ([#758](https://github.com/homarr-labs/homarr/issues/758)) ([0a3d1e9](https://github.com/homarr-labs/homarr/commit/0a3d1e9e5e6682b438b5f3782bdaa305068e0cb7)) +* **deps:** update dependency drizzle-orm to ^0.31.4 ([#759](https://github.com/homarr-labs/homarr/issues/759)) ([8d42ca8](https://github.com/homarr-labs/homarr/commit/8d42ca8b5e63071ceaaf731198ee4633e77d96ac)) +* **deps:** update dependency drizzle-orm to ^0.32.0 ([#776](https://github.com/homarr-labs/homarr/issues/776)) ([3da5734](https://github.com/homarr-labs/homarr/commit/3da5734571de98ceaf2a915a56c177b564beedab)) +* **deps:** update dependency drizzle-orm to ^0.32.1 ([#859](https://github.com/homarr-labs/homarr/issues/859)) ([868b7b8](https://github.com/homarr-labs/homarr/commit/868b7b890e7affbb79935dc78eaac463d660e413)) +* **deps:** update dependency drizzle-orm to ^0.32.2 ([#919](https://github.com/homarr-labs/homarr/issues/919)) ([3f35163](https://github.com/homarr-labs/homarr/commit/3f35163481c85f434a60438ea7425a75b4b2285d)) +* **deps:** update dependency drizzle-orm to ^0.33.0 ([#938](https://github.com/homarr-labs/homarr/issues/938)) ([c399d83](https://github.com/homarr-labs/homarr/commit/c399d832e58edce29b5bc657ff10970c50123a85)) +* **deps:** update dependency drizzle-orm to ^0.34.0 ([#1262](https://github.com/homarr-labs/homarr/issues/1262)) ([23ee229](https://github.com/homarr-labs/homarr/commit/23ee229906b3dab7f7b93e93f76c11aa4ca89392)) +* **deps:** update dependency drizzle-orm to ^0.34.1 ([#1268](https://github.com/homarr-labs/homarr/issues/1268)) ([14d1ce8](https://github.com/homarr-labs/homarr/commit/14d1ce842a011dbe84259ba3509d9edfcdf573e0)) +* **deps:** update dependency drizzle-orm to ^0.35.0 ([#1302](https://github.com/homarr-labs/homarr/issues/1302)) ([c6daccb](https://github.com/homarr-labs/homarr/commit/c6daccbdf0b6a531274c0ab86779ec3f946ebf38)) +* **deps:** update dependency drizzle-orm to ^0.35.1 ([#1306](https://github.com/homarr-labs/homarr/issues/1306)) ([c053a37](https://github.com/homarr-labs/homarr/commit/c053a373b48ed6cc2f877c581e03264288bbe751)) +* **deps:** update dependency drizzle-orm to ^0.35.2 ([#1321](https://github.com/homarr-labs/homarr/issues/1321)) ([c8b1bb8](https://github.com/homarr-labs/homarr/commit/c8b1bb8d62e5c608e37cd28a85c0e7fc12eaf102)) +* **deps:** update dependency drizzle-orm to ^0.35.3 ([#1348](https://github.com/homarr-labs/homarr/issues/1348)) ([85a5ebd](https://github.com/homarr-labs/homarr/commit/85a5ebd288807373f38552d09392be184c3a8caf)) +* **deps:** update dependency drizzle-orm to ^0.36.0 ([#1390](https://github.com/homarr-labs/homarr/issues/1390)) ([3c3dbf5](https://github.com/homarr-labs/homarr/commit/3c3dbf51dc2e702a5eb302dac88986d61aba5881)) +* **deps:** update dependency drizzle-orm to ^0.36.1 ([#1440](https://github.com/homarr-labs/homarr/issues/1440)) ([7966476](https://github.com/homarr-labs/homarr/commit/7966476cad956b20940fd4d7d9df004dd886f7ff)) +* **deps:** update dependency drizzle-orm to ^0.36.2 ([#1481](https://github.com/homarr-labs/homarr/issues/1481)) ([9bc5856](https://github.com/homarr-labs/homarr/commit/9bc585648c8926123c718a3c922ad25c2cd7b897)) +* **deps:** update dependency drizzle-orm to ^0.36.3 ([#1487](https://github.com/homarr-labs/homarr/issues/1487)) ([2fb014f](https://github.com/homarr-labs/homarr/commit/2fb014f2df295cc16a01cc613db6d04fc483793c)) +* **deps:** update dependency drizzle-orm to ^0.36.4 ([#1522](https://github.com/homarr-labs/homarr/issues/1522)) ([50c9683](https://github.com/homarr-labs/homarr/commit/50c96833a697b09cadb8a7c64b2340e2c7b4d292)) +* **deps:** update dependency drizzle-orm to ^0.37.0 ([#1592](https://github.com/homarr-labs/homarr/issues/1592)) ([16cf818](https://github.com/homarr-labs/homarr/commit/16cf818449cd10f14e5235d5afdefaf0f8f01336)) +* **deps:** update dependency drizzle-orm to ^0.38.0 ([#1631](https://github.com/homarr-labs/homarr/issues/1631)) ([2825c9b](https://github.com/homarr-labs/homarr/commit/2825c9bf45c52cf7ec0785774038d9c01ac80cf9)) +* **deps:** update dependency drizzle-orm to ^0.38.1 ([#1646](https://github.com/homarr-labs/homarr/issues/1646)) ([7d0a224](https://github.com/homarr-labs/homarr/commit/7d0a224a3fe70c941ecea6dce9e376c395d8c5bb)) +* **deps:** update dependency drizzle-orm to ^0.38.2 ([#1652](https://github.com/homarr-labs/homarr/issues/1652)) ([da63d8e](https://github.com/homarr-labs/homarr/commit/da63d8ebf4b56caa34896d3b41d4784cd333123c)) +* **deps:** update dependency drizzle-zod to ^0.6.0 ([#1629](https://github.com/homarr-labs/homarr/issues/1629)) ([51c87c1](https://github.com/homarr-labs/homarr/commit/51c87c1a33ca5fc2e583e27c33dd8828ac134e41)) +* **deps:** update dependency eslint-config-turbo to ^1.12.2 ([#34](https://github.com/homarr-labs/homarr/issues/34)) ([837e390](https://github.com/homarr-labs/homarr/commit/837e3900fa905e3d96d1b7693a889eb99ac71c1f)) +* **deps:** update dependency eslint-config-turbo to ^2.0.13 ([#978](https://github.com/homarr-labs/homarr/issues/978)) ([497363b](https://github.com/homarr-labs/homarr/commit/497363b4912a1b0d42abd9414b7ff827223220a0)) +* **deps:** update dependency eslint-config-turbo to ^2.0.14 ([#984](https://github.com/homarr-labs/homarr/issues/984)) ([5e7ee1b](https://github.com/homarr-labs/homarr/commit/5e7ee1b657cb55826518841e1dcb25cce4050bad)) +* **deps:** update dependency eslint-plugin-import to ^2.29.1 ([#23](https://github.com/homarr-labs/homarr/issues/23)) ([f3bb990](https://github.com/homarr-labs/homarr/commit/f3bb990c4dcd40f367cf59a120cf8f6fd2658309)) +* **deps:** update dependency eslint-plugin-import to ^2.30.0 ([#1061](https://github.com/homarr-labs/homarr/issues/1061)) ([0f34bf8](https://github.com/homarr-labs/homarr/commit/0f34bf85a8476b73140c2b6b8baad87fa924ebdb)) +* **deps:** update dependency eslint-plugin-import to ^2.31.0 ([#1226](https://github.com/homarr-labs/homarr/issues/1226)) ([9d20362](https://github.com/homarr-labs/homarr/commit/9d20362cf1323c57e7ed7dc9ba4e234c51ccc1d0)) +* **deps:** update dependency eslint-plugin-jsx-a11y to ^6.10.0 ([#1066](https://github.com/homarr-labs/homarr/issues/1066)) ([bef5832](https://github.com/homarr-labs/homarr/commit/bef5832470012ff8eeddd2e95822800f4c349491)) +* **deps:** update dependency eslint-plugin-jsx-a11y to ^6.10.1 ([#1343](https://github.com/homarr-labs/homarr/issues/1343)) ([564096e](https://github.com/homarr-labs/homarr/commit/564096e463b25c243c7f2adb2c9b059c940365fe)) +* **deps:** update dependency eslint-plugin-jsx-a11y to ^6.10.2 ([#1374](https://github.com/homarr-labs/homarr/issues/1374)) ([3127182](https://github.com/homarr-labs/homarr/commit/3127182f5c16a6c792557c9f458b7e20511cdf8f)) +* **deps:** update dependency eslint-plugin-jsx-a11y to ^6.9.0 ([#695](https://github.com/homarr-labs/homarr/issues/695)) ([d78b581](https://github.com/homarr-labs/homarr/commit/d78b581104009d92a835d99978e935059682b7e2)) +* **deps:** update dependency eslint-plugin-react to ^7.34.0 ([#189](https://github.com/homarr-labs/homarr/issues/189)) ([4cd897d](https://github.com/homarr-labs/homarr/commit/4cd897d521ba11a69cc5f7960746dfbb5d10bd44)) +* **deps:** update dependency eslint-plugin-react to ^7.34.1 ([#240](https://github.com/homarr-labs/homarr/issues/240)) ([404f294](https://github.com/homarr-labs/homarr/commit/404f2945dc0db083ad4adb941f436b7cbd04ce6d)) +* **deps:** update dependency eslint-plugin-react to ^7.34.2 ([#567](https://github.com/homarr-labs/homarr/issues/567)) ([9e499bd](https://github.com/homarr-labs/homarr/commit/9e499bd30ba5a8d22f15ef7e4e467090268125e7)) +* **deps:** update dependency eslint-plugin-react to ^7.34.3 ([#688](https://github.com/homarr-labs/homarr/issues/688)) ([fdcf3a8](https://github.com/homarr-labs/homarr/commit/fdcf3a89c929de9d441898f31bfeb141613fe9ff)) +* **deps:** update dependency eslint-plugin-react to ^7.34.4 ([#809](https://github.com/homarr-labs/homarr/issues/809)) ([fd64201](https://github.com/homarr-labs/homarr/commit/fd642011ba8bd11e03de46e35de387da819d5c98)) +* **deps:** update dependency eslint-plugin-react to ^7.35.0 ([#835](https://github.com/homarr-labs/homarr/issues/835)) ([37a8a0f](https://github.com/homarr-labs/homarr/commit/37a8a0fe5aebe813ba9be05643b1333485e20d5f)) +* **deps:** update dependency eslint-plugin-react to ^7.35.1 ([#1059](https://github.com/homarr-labs/homarr/issues/1059)) ([4c52cc3](https://github.com/homarr-labs/homarr/commit/4c52cc338e0bca1d9a80d23a3b409526109206b5)) +* **deps:** update dependency eslint-plugin-react to ^7.35.2 ([#1062](https://github.com/homarr-labs/homarr/issues/1062)) ([1249fb9](https://github.com/homarr-labs/homarr/commit/1249fb96122597f2d40cc5719d687354b7c1411c)) +* **deps:** update dependency eslint-plugin-react to ^7.36.0 ([#1111](https://github.com/homarr-labs/homarr/issues/1111)) ([cd43253](https://github.com/homarr-labs/homarr/commit/cd43253061c4162d1c1835b3cbb843250d0d5b51)) +* **deps:** update dependency eslint-plugin-react to ^7.36.1 ([#1115](https://github.com/homarr-labs/homarr/issues/1115)) ([2351617](https://github.com/homarr-labs/homarr/commit/2351617177d334467e26c08c378da4994f21f581)) +* **deps:** update dependency eslint-plugin-react to ^7.37.0 ([#1189](https://github.com/homarr-labs/homarr/issues/1189)) ([2245e7a](https://github.com/homarr-labs/homarr/commit/2245e7aae8fa75730706d2e73c30870ac6d0ec77)) +* **deps:** update dependency eslint-plugin-react to ^7.37.1 ([#1213](https://github.com/homarr-labs/homarr/issues/1213)) ([4a8ed13](https://github.com/homarr-labs/homarr/commit/4a8ed13a87ff44aed89754fbc171db0641cf78d8)) +* **deps:** update dependency eslint-plugin-react to ^7.37.2 ([#1354](https://github.com/homarr-labs/homarr/issues/1354)) ([1a2f0ad](https://github.com/homarr-labs/homarr/commit/1a2f0adfc8d22eade925409aac63ccb9d8885c08)) +* **deps:** update dependency eslint-plugin-react-hooks to ^5.1.0 ([#1614](https://github.com/homarr-labs/homarr/issues/1614)) ([6d6840f](https://github.com/homarr-labs/homarr/commit/6d6840f85e5f38b2f7ec990cf7402de86ea84166)) +* **deps:** update dependency eslint-plugin-react-hooks to v5 ([#1280](https://github.com/homarr-labs/homarr/issues/1280)) ([a87c937](https://github.com/homarr-labs/homarr/commit/a87c937b69550160cc10e9991256c032245fcbfc)) +* **deps:** update dependency flag-icons to ^7.2.2 ([#533](https://github.com/homarr-labs/homarr/issues/533)) ([f45fa50](https://github.com/homarr-labs/homarr/commit/f45fa500248d810aadb05cf2ad8ecd247bcae60b)) +* **deps:** update dependency flag-icons to ^7.2.3 ([#575](https://github.com/homarr-labs/homarr/issues/575)) ([fe43e74](https://github.com/homarr-labs/homarr/commit/fe43e74c5399942c6cb099352fc1098fe1261fc4)) +* **deps:** update dependency glob to ^10.3.14 ([#461](https://github.com/homarr-labs/homarr/issues/461)) ([8bd08d3](https://github.com/homarr-labs/homarr/commit/8bd08d39ca106b225aee123278b1387d037feedc)) +* **deps:** update dependency glob to ^10.3.15 ([#478](https://github.com/homarr-labs/homarr/issues/478)) ([333b124](https://github.com/homarr-labs/homarr/commit/333b124f678818b346816bbd29f6bc78f20e175d)) +* **deps:** update dependency glob to ^10.4.1 ([#531](https://github.com/homarr-labs/homarr/issues/531)) ([a0322bf](https://github.com/homarr-labs/homarr/commit/a0322bfd994c9fae57f7d8f7e219d0ac70d7868c)) +* **deps:** update dependency glob to ^10.4.2 ([#689](https://github.com/homarr-labs/homarr/issues/689)) ([0bfc0c5](https://github.com/homarr-labs/homarr/commit/0bfc0c5d2543677b7efe6fcec1af7c72e178af1b)) +* **deps:** update dependency glob to ^10.4.3 ([#751](https://github.com/homarr-labs/homarr/issues/751)) ([61cbb74](https://github.com/homarr-labs/homarr/commit/61cbb74d14b93ee9e52a2170a4ff01c93dcd09c1)) +* **deps:** update dependency glob to ^10.4.4 ([#765](https://github.com/homarr-labs/homarr/issues/765)) ([74b017d](https://github.com/homarr-labs/homarr/commit/74b017d9f4b39b9d6de0d76f180fcf5c6f145215)) +* **deps:** update dependency glob to ^10.4.5 ([#768](https://github.com/homarr-labs/homarr/issues/768)) ([4cee3df](https://github.com/homarr-labs/homarr/commit/4cee3dfbe00cd984e31a732e88bc581606ab37e9)) +* **deps:** update dependency glob to v10.4.1 ([#544](https://github.com/homarr-labs/homarr/issues/544)) ([7b46d92](https://github.com/homarr-labs/homarr/commit/7b46d92d4f992584c813cc2d7e99813f53a8b72e)) +* **deps:** update dependency glob to v11 ([#766](https://github.com/homarr-labs/homarr/issues/766)) ([0169501](https://github.com/homarr-labs/homarr/commit/0169501676aa8d1170ee44aa0bb8134d994d472e)) +* **deps:** update dependency ioredis to v5.4.1 ([#357](https://github.com/homarr-labs/homarr/issues/357)) ([20f44d3](https://github.com/homarr-labs/homarr/commit/20f44d3494ffbe76994e6d541d31ced2cfd8abd3)) +* **deps:** update dependency jotai to ^2.10.0 ([#1155](https://github.com/homarr-labs/homarr/issues/1155)) ([dd9080f](https://github.com/homarr-labs/homarr/commit/dd9080f781b782a1a112c53f1af1e987fde22e32)) +* **deps:** update dependency jotai to ^2.10.1 ([#1295](https://github.com/homarr-labs/homarr/issues/1295)) ([ba81e5e](https://github.com/homarr-labs/homarr/commit/ba81e5e35a046e8dda1c2660beff1e1644d4d32a)) +* **deps:** update dependency jotai to ^2.10.2 ([#1464](https://github.com/homarr-labs/homarr/issues/1464)) ([75d764b](https://github.com/homarr-labs/homarr/commit/75d764bca83e41bc932a4aed5244bf6922d2d070)) +* **deps:** update dependency jotai to ^2.10.3 ([#1509](https://github.com/homarr-labs/homarr/issues/1509)) ([ae61377](https://github.com/homarr-labs/homarr/commit/ae6137710f51c3f53127a779793ce2d1566e7e0d)) +* **deps:** update dependency jotai to ^2.10.4 ([#1672](https://github.com/homarr-labs/homarr/issues/1672)) ([b7b5da6](https://github.com/homarr-labs/homarr/commit/b7b5da654bee37f1aceda2718bb92646fc4f472e)) +* **deps:** update dependency jotai to ^2.6.4 ([#24](https://github.com/homarr-labs/homarr/issues/24)) ([a7d5c36](https://github.com/homarr-labs/homarr/commit/a7d5c36aa798ea9cf03579b752fa3640fb4f79cf)) +* **deps:** update dependency jotai to ^2.6.5 ([#106](https://github.com/homarr-labs/homarr/issues/106)) ([fc8d907](https://github.com/homarr-labs/homarr/commit/fc8d9071aa91afdb00b17b1de13a61241aa93705)) +* **deps:** update dependency jotai to ^2.7.0 ([#162](https://github.com/homarr-labs/homarr/issues/162)) ([af203e1](https://github.com/homarr-labs/homarr/commit/af203e19e76450e990384443e9d9de1e1df7748f)) +* **deps:** update dependency jotai to ^2.7.1 ([#238](https://github.com/homarr-labs/homarr/issues/238)) ([75ab823](https://github.com/homarr-labs/homarr/commit/75ab8230196272e2c713b948a614b3ac0ce62f09)) +* **deps:** update dependency jotai to ^2.7.2 ([#284](https://github.com/homarr-labs/homarr/issues/284)) ([d06528f](https://github.com/homarr-labs/homarr/commit/d06528f3119e18ddf09ab210fa2dd7ed1570bd5f)) +* **deps:** update dependency jotai to ^2.8.0 ([#326](https://github.com/homarr-labs/homarr/issues/326)) ([27c858d](https://github.com/homarr-labs/homarr/commit/27c858dc815f8d450310a219d2ec44093f33b293)) +* **deps:** update dependency jotai to ^2.8.1 ([#534](https://github.com/homarr-labs/homarr/issues/534)) ([c668d0a](https://github.com/homarr-labs/homarr/commit/c668d0a76502ce082990e7e64b7e7c801f33134f)) +* **deps:** update dependency jotai to ^2.8.2 ([#561](https://github.com/homarr-labs/homarr/issues/561)) ([6f47adf](https://github.com/homarr-labs/homarr/commit/6f47adff8abfdd1e94207a73fa6638e9aa11d396)) +* **deps:** update dependency jotai to ^2.8.3 ([#615](https://github.com/homarr-labs/homarr/issues/615)) ([d993e8d](https://github.com/homarr-labs/homarr/commit/d993e8d81136f8fb42a27b082d41b00bd5c2668a)) +* **deps:** update dependency jotai to ^2.8.4 ([#721](https://github.com/homarr-labs/homarr/issues/721)) ([e46bfd9](https://github.com/homarr-labs/homarr/commit/e46bfd9146929421434ce847352ce8b7a08106f7)) +* **deps:** update dependency jotai to ^2.9.0 ([#767](https://github.com/homarr-labs/homarr/issues/767)) ([5e3dc1e](https://github.com/homarr-labs/homarr/commit/5e3dc1e44dbe229870637c58188c6b6057092a95)) +* **deps:** update dependency jotai to ^2.9.1 ([#858](https://github.com/homarr-labs/homarr/issues/858)) ([fc5f02b](https://github.com/homarr-labs/homarr/commit/fc5f02b022786e7ec75c900d33c2386c71a77e53)) +* **deps:** update dependency jotai to ^2.9.2 ([#933](https://github.com/homarr-labs/homarr/issues/933)) ([c2bf677](https://github.com/homarr-labs/homarr/commit/c2bf6779c0664720a180192813ed4bfab02bf0e1)) +* **deps:** update dependency jotai to ^2.9.3 ([#969](https://github.com/homarr-labs/homarr/issues/969)) ([9d62fb4](https://github.com/homarr-labs/homarr/commit/9d62fb42c470d09c8891bdb8997af75926f3d03d)) +* **deps:** update dependency ldapts to v7.1.0 ([#839](https://github.com/homarr-labs/homarr/issues/839)) ([c33086d](https://github.com/homarr-labs/homarr/commit/c33086d8b55be9ba605c1f2c7429e44bd6ddada1)) +* **deps:** update dependency ldapts to v7.1.1 ([#1038](https://github.com/homarr-labs/homarr/issues/1038)) ([b507bf2](https://github.com/homarr-labs/homarr/commit/b507bf2ae67120ab7089297d53ce41c26314ca30)) +* **deps:** update dependency ldapts to v7.2.0 ([#1097](https://github.com/homarr-labs/homarr/issues/1097)) ([9d5007c](https://github.com/homarr-labs/homarr/commit/9d5007c05cb3216c9acbb1233326be1cd8d1cbb8)) +* **deps:** update dependency ldapts to v7.2.1 ([#1211](https://github.com/homarr-labs/homarr/issues/1211)) ([1b0d927](https://github.com/homarr-labs/homarr/commit/1b0d927e8866376f2f6851f78f9ef5ab67eb5ad2)) +* **deps:** update dependency ldapts to v7.2.2 ([#1574](https://github.com/homarr-labs/homarr/issues/1574)) ([d5f7621](https://github.com/homarr-labs/homarr/commit/d5f76218cd314769fb312e60de824acc1f90914e)) +* **deps:** update dependency mantine-modal-manager to ^7.5.2 ([#72](https://github.com/homarr-labs/homarr/issues/72)) ([f704bad](https://github.com/homarr-labs/homarr/commit/f704bad36e103fc349b0303d9f79440d076c1e88)) +* **deps:** update dependency mantine-modal-manager to ^7.5.3 ([#132](https://github.com/homarr-labs/homarr/issues/132)) ([4565f38](https://github.com/homarr-labs/homarr/commit/4565f38bef6e940c2856b7213dae92cfff659a7b)) +* **deps:** update dependency mantine-modal-manager to ^7.6.1 ([#171](https://github.com/homarr-labs/homarr/issues/171)) ([acf9d18](https://github.com/homarr-labs/homarr/commit/acf9d1803f7112520a87fe854ef65d7f67dd5cb9)) +* **deps:** update dependency mantine-modal-manager to ^7.6.2 ([#222](https://github.com/homarr-labs/homarr/issues/222)) ([b63b2c8](https://github.com/homarr-labs/homarr/commit/b63b2c8e9021d8e789789471a061f1f40320a135)) +* **deps:** update dependency mantine-react-table to v2.0.0-beta.0 ([#149](https://github.com/homarr-labs/homarr/issues/149)) ([f211ffb](https://github.com/homarr-labs/homarr/commit/f211ffbf78d9039fc5e68a8219cef134ad3a5fa5)) +* **deps:** update dependency mantine-react-table to v2.0.0-beta.1 ([#277](https://github.com/homarr-labs/homarr/issues/277)) ([e1b62ec](https://github.com/homarr-labs/homarr/commit/e1b62ecd5300b54523e9c9672b53b9ac49a3996e)) +* **deps:** update dependency mantine-react-table to v2.0.0-beta.2 ([#466](https://github.com/homarr-labs/homarr/issues/466)) ([627f895](https://github.com/homarr-labs/homarr/commit/627f8957e546a37520f0122b62664704f9d286c3)) +* **deps:** update dependency mantine-react-table to v2.0.0-beta.3 ([#488](https://github.com/homarr-labs/homarr/issues/488)) ([8b84695](https://github.com/homarr-labs/homarr/commit/8b84695079220228e99317d9cd12d613e6af4043)) +* **deps:** update dependency mantine-react-table to v2.0.0-beta.4 ([#593](https://github.com/homarr-labs/homarr/issues/593)) ([fef070c](https://github.com/homarr-labs/homarr/commit/fef070c42cbff79e8301fdbe5623482d2ed01521)) +* **deps:** update dependency mantine-react-table to v2.0.0-beta.5 ([#661](https://github.com/homarr-labs/homarr/issues/661)) ([37ebcfe](https://github.com/homarr-labs/homarr/commit/37ebcfe318540e6941ea62a40a001aaed19e0abf)) +* **deps:** update dependency mantine-react-table to v2.0.0-beta.6 ([#837](https://github.com/homarr-labs/homarr/issues/837)) ([5da74ca](https://github.com/homarr-labs/homarr/commit/5da74ca7e057632b9f693061c3855e1fb348c5bb)) +* **deps:** update dependency mantine-react-table to v2.0.0-beta.7 ([#1287](https://github.com/homarr-labs/homarr/issues/1287)) ([6f97741](https://github.com/homarr-labs/homarr/commit/6f97741862ad2d25d852858e509f78d0ff0a7e01)) +* **deps:** update dependency mysql2 to ^3.9.3 ([#273](https://github.com/homarr-labs/homarr/issues/273)) ([b0bba14](https://github.com/homarr-labs/homarr/commit/b0bba1418b802b238eb8724987ce6bbb1a27f195)) +* **deps:** update dependency mysql2 to v3.10.0 ([#585](https://github.com/homarr-labs/homarr/issues/585)) ([ff84c2b](https://github.com/homarr-labs/homarr/commit/ff84c2bdb77db1e825fd3a6c7be303f2c450edbe)) +* **deps:** update dependency mysql2 to v3.10.1 ([#665](https://github.com/homarr-labs/homarr/issues/665)) ([10acb2b](https://github.com/homarr-labs/homarr/commit/10acb2bc7645048c8265a78075eef6ac6f0b1fe0)) +* **deps:** update dependency mysql2 to v3.10.2 ([#731](https://github.com/homarr-labs/homarr/issues/731)) ([663eb0b](https://github.com/homarr-labs/homarr/commit/663eb0bf5b986a71c36a36f86e5011835112d2b7)) +* **deps:** update dependency mysql2 to v3.10.3 ([#816](https://github.com/homarr-labs/homarr/issues/816)) ([636d3c6](https://github.com/homarr-labs/homarr/commit/636d3c670cc387a26112d58a33576cdcd1e5b5d2)) +* **deps:** update dependency mysql2 to v3.11.0 ([#874](https://github.com/homarr-labs/homarr/issues/874)) ([c973a3b](https://github.com/homarr-labs/homarr/commit/c973a3bfa540397b6882e0b4bdd5ce6c2a193e2f)) +* **deps:** update dependency mysql2 to v3.11.1 ([#1094](https://github.com/homarr-labs/homarr/issues/1094)) ([40af170](https://github.com/homarr-labs/homarr/commit/40af17083aba37c2e02f81f295c1192f70d0a691)) +* **deps:** update dependency mysql2 to v3.11.2 ([#1098](https://github.com/homarr-labs/homarr/issues/1098)) ([d2a30db](https://github.com/homarr-labs/homarr/commit/d2a30db3c1bd21decba0624c13635b092afabf4f)) +* **deps:** update dependency mysql2 to v3.11.3 ([#1132](https://github.com/homarr-labs/homarr/issues/1132)) ([6c39612](https://github.com/homarr-labs/homarr/commit/6c39612c0731c0728b62057eb240543ae4a1ec15)) +* **deps:** update dependency mysql2 to v3.11.4 ([#1430](https://github.com/homarr-labs/homarr/issues/1430)) ([7e1305c](https://github.com/homarr-labs/homarr/commit/7e1305c6a99e96900b447591ebeb48393186483d)) +* **deps:** update dependency mysql2 to v3.11.5 ([#1567](https://github.com/homarr-labs/homarr/issues/1567)) ([cebc925](https://github.com/homarr-labs/homarr/commit/cebc925b879d22a662be326c6b8b5048907dd92c)) +* **deps:** update dependency mysql2 to v3.9.6 ([#311](https://github.com/homarr-labs/homarr/issues/311)) ([a6d65fd](https://github.com/homarr-labs/homarr/commit/a6d65fda6b9ed31a08a420e51718dbd36f8da7ae)) +* **deps:** update dependency mysql2 to v3.9.7 ([#369](https://github.com/homarr-labs/homarr/issues/369)) ([51ea67f](https://github.com/homarr-labs/homarr/commit/51ea67fc883a6b2e2164f46a6a3e1e41a961a834)) +* **deps:** update dependency mysql2 to v3.9.8 ([#558](https://github.com/homarr-labs/homarr/issues/558)) ([3f364ca](https://github.com/homarr-labs/homarr/commit/3f364cacedb556cb58c8b15c1a81cecca7cb22e7)) +* **deps:** update dependency mysql2 to v3.9.9 ([#576](https://github.com/homarr-labs/homarr/issues/576)) ([612b8d8](https://github.com/homarr-labs/homarr/commit/612b8d8c6eff4adaec8e359b4733af31c69e10ae)) +* **deps:** update dependency next to ^14.1.1-canary.59 ([#121](https://github.com/homarr-labs/homarr/issues/121)) ([4f911c4](https://github.com/homarr-labs/homarr/commit/4f911c4f56be487726359eb00e7d34bff426b596)) +* **deps:** update dependency next to ^14.1.1-canary.61 ([#138](https://github.com/homarr-labs/homarr/issues/138)) ([6a02afb](https://github.com/homarr-labs/homarr/commit/6a02afbfe2daded6a86ee13423ae4fdeb7ed14a5)) +* **deps:** update dependency next to ^14.1.1-canary.62 ([#140](https://github.com/homarr-labs/homarr/issues/140)) ([fde634d](https://github.com/homarr-labs/homarr/commit/fde634d834c58501435ccab7409693fd9f5fecbc)) +* **deps:** update dependency next to ^14.1.1-canary.63 ([#146](https://github.com/homarr-labs/homarr/issues/146)) ([4d01136](https://github.com/homarr-labs/homarr/commit/4d011364bf61971392b541d6758585eb25f5c68c)) +* **deps:** update dependency next-auth to v5.0.0-beta.11 ([#91](https://github.com/homarr-labs/homarr/issues/91)) ([336dc38](https://github.com/homarr-labs/homarr/commit/336dc38b2d0f6932eaacee354640ffa5ec92729e)) +* **deps:** update dependency next-auth to v5.0.0-beta.13 ([#108](https://github.com/homarr-labs/homarr/issues/108)) ([64194c5](https://github.com/homarr-labs/homarr/commit/64194c51edbca639193d9865fc6d4c7e07a1b3bf)) +* **deps:** update dependency next-auth to v5.0.0-beta.15 ([#167](https://github.com/homarr-labs/homarr/issues/167)) ([70f34ef](https://github.com/homarr-labs/homarr/commit/70f34efd5385e641bf5f9f043cbd18e6e9bf2cce)) +* **deps:** update dependency next-auth to v5.0.0-beta.16 ([#268](https://github.com/homarr-labs/homarr/issues/268)) ([ba27871](https://github.com/homarr-labs/homarr/commit/ba278717650a20381912070624aa390594410578)) +* **deps:** update dependency next-auth to v5.0.0-beta.17 ([#383](https://github.com/homarr-labs/homarr/issues/383)) ([bfdc8d5](https://github.com/homarr-labs/homarr/commit/bfdc8d584b9abef5bf3b417ad8eba951404856ce)) +* **deps:** update dependency next-auth to v5.0.0-beta.19 ([#605](https://github.com/homarr-labs/homarr/issues/605)) ([20874cb](https://github.com/homarr-labs/homarr/commit/20874cb96d7b45ca33bd86e3670d81dc71688390)) +* **deps:** update dependency next-auth to v5.0.0-beta.20 ([#878](https://github.com/homarr-labs/homarr/issues/878)) ([a0c5545](https://github.com/homarr-labs/homarr/commit/a0c55459d1e3dbec93329ca9c99acf652683a08b)) +* **deps:** update dependency next-auth to v5.0.0-beta.21 ([#1131](https://github.com/homarr-labs/homarr/issues/1131)) ([5a73700](https://github.com/homarr-labs/homarr/commit/5a73700f571b6628161b55380fd08da93cede0a8)) +* **deps:** update dependency next-auth to v5.0.0-beta.22 ([#1195](https://github.com/homarr-labs/homarr/issues/1195)) ([c3e1ce3](https://github.com/homarr-labs/homarr/commit/c3e1ce30fa15ff7cee29d842a2f6c8688f9639ba)) +* **deps:** update dependency next-auth to v5.0.0-beta.23 ([#1325](https://github.com/homarr-labs/homarr/issues/1325)) ([c52fd97](https://github.com/homarr-labs/homarr/commit/c52fd972b7157d6132923cff5c2c350ca32d8229)) +* **deps:** update dependency next-auth to v5.0.0-beta.25 ([#1341](https://github.com/homarr-labs/homarr/issues/1341)) ([278107a](https://github.com/homarr-labs/homarr/commit/278107a1a4b6c5f6b391a25704314c613212fbab)) +* **deps:** update dependency next-auth to v5.0.0-beta.8 ([#60](https://github.com/homarr-labs/homarr/issues/60)) ([544a6d9](https://github.com/homarr-labs/homarr/commit/544a6d992691c6ba398b236fdd4f59111fa64e5a)) +* **deps:** update dependency next-auth to v5.0.0-beta.9 ([#68](https://github.com/homarr-labs/homarr/issues/68)) ([cc52c2b](https://github.com/homarr-labs/homarr/commit/cc52c2ba785e78f251bc6cfac637bc4285b77f0f)) +* **deps:** update dependency next-international to ^1.2.3 ([#35](https://github.com/homarr-labs/homarr/issues/35)) ([b8fe041](https://github.com/homarr-labs/homarr/commit/b8fe04144fea31a934a59094c52d7c6fc4cfffbb)) +* **deps:** update dependency next-international to ^1.2.4 ([#76](https://github.com/homarr-labs/homarr/issues/76)) ([60d5ebb](https://github.com/homarr-labs/homarr/commit/60d5ebbc11fd8a8f5494e303335e2bd46ec09a3d)) +* **deps:** update dependency next-intl to v3.23.5 ([#1376](https://github.com/homarr-labs/homarr/issues/1376)) ([a4ae38b](https://github.com/homarr-labs/homarr/commit/a4ae38b5e4bf09303e659f4eacac0c81ea3bea07)) +* **deps:** update dependency next-intl to v3.24.0 ([#1392](https://github.com/homarr-labs/homarr/issues/1392)) ([4e9b0af](https://github.com/homarr-labs/homarr/commit/4e9b0af54c2f3bc5a23b9cecfc570b74787af478)) +* **deps:** update dependency next-intl to v3.25.0 ([#1448](https://github.com/homarr-labs/homarr/issues/1448)) ([8722109](https://github.com/homarr-labs/homarr/commit/87221093d25df689472ed86184d528eb815e10d1)) +* **deps:** update dependency next-intl to v3.25.1 ([#1473](https://github.com/homarr-labs/homarr/issues/1473)) ([7a9e9a1](https://github.com/homarr-labs/homarr/commit/7a9e9a1e0de02a678787c2509e09c748d7a0042b)) +* **deps:** update dependency next-intl to v3.25.2 ([#1545](https://github.com/homarr-labs/homarr/issues/1545)) ([b6c28da](https://github.com/homarr-labs/homarr/commit/b6c28da32b0cdcfe181db8e698e9f28997cebc52)) +* **deps:** update dependency next-intl to v3.25.3 ([#1551](https://github.com/homarr-labs/homarr/issues/1551)) ([907c28c](https://github.com/homarr-labs/homarr/commit/907c28c945bc7e7ac2c600f7c7a04750ff7465d6)) +* **deps:** update dependency next-intl to v3.26.0 ([#1619](https://github.com/homarr-labs/homarr/issues/1619)) ([58008c1](https://github.com/homarr-labs/homarr/commit/58008c1e2fc9a20401f45288f3beedb80a466351)) +* **deps:** update dependency next-intl to v3.26.1 ([#1644](https://github.com/homarr-labs/homarr/issues/1644)) ([5194867](https://github.com/homarr-labs/homarr/commit/51948677fa1fd0b6ea7410cdbb6f6f77a1f87db0)) +* **deps:** update dependency node-cron to ^3.0.3 ([#309](https://github.com/homarr-labs/homarr/issues/309)) ([48f45d7](https://github.com/homarr-labs/homarr/commit/48f45d73775f0b872613e01edc3499a2a2f7c924)) +* **deps:** update dependency postcss-preset-mantine to ^1.13.0 ([#36](https://github.com/homarr-labs/homarr/issues/36)) ([d73e7a3](https://github.com/homarr-labs/homarr/commit/d73e7a3c3fc278e30f723a5d2b4bdedf667cc5ce)) +* **deps:** update dependency postcss-preset-mantine to ^1.14.4 ([#336](https://github.com/homarr-labs/homarr/issues/336)) ([49e45e8](https://github.com/homarr-labs/homarr/commit/49e45e8122147b2eeebc5ee025bdfd91e7cb4836)) +* **deps:** update dependency postcss-preset-mantine to ^1.15.0 ([#387](https://github.com/homarr-labs/homarr/issues/387)) ([84175e6](https://github.com/homarr-labs/homarr/commit/84175e6a7e4fb8ce3cbcb89ee4d713b6531d3ac0)) +* **deps:** update dependency postcss-preset-mantine to ^1.16.0 ([#827](https://github.com/homarr-labs/homarr/issues/827)) ([002d011](https://github.com/homarr-labs/homarr/commit/002d011b18ffa74f29d06a6bef3d08d6e997735d)) +* **deps:** update dependency postcss-preset-mantine to ^1.17.0 ([#843](https://github.com/homarr-labs/homarr/issues/843)) ([41e5760](https://github.com/homarr-labs/homarr/commit/41e576039f8400e671dd52362a6b2ba9ce605a9f)) +* **deps:** update dependency prettier to ^3.2.4 ([#37](https://github.com/homarr-labs/homarr/issues/37)) ([9aaec54](https://github.com/homarr-labs/homarr/commit/9aaec5495dfacbbf2a313d142e23394bf8c78d43)) +* **deps:** update dependency prettier to ^3.2.5 ([#53](https://github.com/homarr-labs/homarr/issues/53)) ([15f0801](https://github.com/homarr-labs/homarr/commit/15f08011a6c2e7fd7274bc28b9d559269cb03f7e)) +* **deps:** update dependency prettier to ^3.3.0 ([#594](https://github.com/homarr-labs/homarr/issues/594)) ([b1b839f](https://github.com/homarr-labs/homarr/commit/b1b839fcd866f0c157e14d59a47e0cdbeb1ff444)) +* **deps:** update dependency prettier to ^3.3.1 ([#623](https://github.com/homarr-labs/homarr/issues/623)) ([8f551aa](https://github.com/homarr-labs/homarr/commit/8f551aa4856065c3a7e1e7e763781863ed2db972)) +* **deps:** update dependency prettier to ^3.3.2 ([#656](https://github.com/homarr-labs/homarr/issues/656)) ([d69cda0](https://github.com/homarr-labs/homarr/commit/d69cda03136f29744b4935e28bdfc4dcb24424fb)) +* **deps:** update dependency prettier to ^3.3.3 ([#805](https://github.com/homarr-labs/homarr/issues/805)) ([66036b0](https://github.com/homarr-labs/homarr/commit/66036b08bcfecb5fb4e2e588bd74e935a387a34c)) +* **deps:** update dependency prettier to ^3.4.0 ([#1550](https://github.com/homarr-labs/homarr/issues/1550)) ([2e9b99d](https://github.com/homarr-labs/homarr/commit/2e9b99dff76e675a5e28ca22dddc467fe94a5f6d)) +* **deps:** update dependency prettier to ^3.4.1 ([#1554](https://github.com/homarr-labs/homarr/issues/1554)) ([27b8f65](https://github.com/homarr-labs/homarr/commit/27b8f65238eca00e6f51f681c4689199cae22728)) +* **deps:** update dependency prettier to ^3.4.2 ([#1602](https://github.com/homarr-labs/homarr/issues/1602)) ([bbec013](https://github.com/homarr-labs/homarr/commit/bbec01385f8ba609efe83712c61df4c0b483badb)) +* **deps:** update dependency react-error-boundary to ^4.1.0 ([#1304](https://github.com/homarr-labs/homarr/issues/1304)) ([9fa4bef](https://github.com/homarr-labs/homarr/commit/9fa4bef2a4a9edf68299f3095a60d4eaaf144f65)) +* **deps:** update dependency react-error-boundary to ^4.1.1 ([#1315](https://github.com/homarr-labs/homarr/issues/1315)) ([3b5082c](https://github.com/homarr-labs/homarr/commit/3b5082c107771ade24917da61b87321bfc40995d)) +* **deps:** update dependency react-error-boundary to ^4.1.2 ([#1334](https://github.com/homarr-labs/homarr/issues/1334)) ([98f1c33](https://github.com/homarr-labs/homarr/commit/98f1c333186c44f5f1e4bfc6452451edb990cbaa)) +* **deps:** update dependency react-simple-code-editor to ^0.14.0 ([#738](https://github.com/homarr-labs/homarr/issues/738)) ([d32075d](https://github.com/homarr-labs/homarr/commit/d32075d410af5111e4e33c09be7facdd0d44d196)) +* **deps:** update dependency react-simple-code-editor to ^0.14.1 ([#746](https://github.com/homarr-labs/homarr/issues/746)) ([9375738](https://github.com/homarr-labs/homarr/commit/9375738e0552357f53b52c1637732494f568f5a0)) +* **deps:** update dependency reflect-metadata to ^0.2.1 ([#182](https://github.com/homarr-labs/homarr/issues/182)) ([9ee96a1](https://github.com/homarr-labs/homarr/commit/9ee96a14628b3b450d45b07ad45863375b899cde)) +* **deps:** update dependency rimraf to v5 ([#186](https://github.com/homarr-labs/homarr/issues/186)) ([f4b93d1](https://github.com/homarr-labs/homarr/commit/f4b93d1eae4b28cb5929b30ea2a55c57bdac84be)) +* **deps:** update dependency rxjs to ^7.8.1 ([#181](https://github.com/homarr-labs/homarr/issues/181)) ([e1a98f7](https://github.com/homarr-labs/homarr/commit/e1a98f7fc05881c3b161f22463afbcf3b0b306b0)) +* **deps:** update dependency sass to ^1.71.0 ([#96](https://github.com/homarr-labs/homarr/issues/96)) ([9a60588](https://github.com/homarr-labs/homarr/commit/9a60588a031b262a06d4048804960bf7966ba1b5)) +* **deps:** update dependency sass to ^1.71.1 ([#148](https://github.com/homarr-labs/homarr/issues/148)) ([abc4a9a](https://github.com/homarr-labs/homarr/commit/abc4a9afbc7b61266907826da1f20077e98176f2)) +* **deps:** update dependency sass to ^1.72.0 ([#230](https://github.com/homarr-labs/homarr/issues/230)) ([4bab91f](https://github.com/homarr-labs/homarr/commit/4bab91f8deeb65678009edcbff31abe843269d44)) +* **deps:** update dependency sass to ^1.74.1 ([#306](https://github.com/homarr-labs/homarr/issues/306)) ([e68a2e5](https://github.com/homarr-labs/homarr/commit/e68a2e5813d857f1da8bd1ae15129fd323d98f52)) +* **deps:** update dependency sass to ^1.75.0 ([#347](https://github.com/homarr-labs/homarr/issues/347)) ([0cc5225](https://github.com/homarr-labs/homarr/commit/0cc5225e32b18cf02378836bc4142663c68aa82d)) +* **deps:** update dependency sass to ^1.76.0 ([#410](https://github.com/homarr-labs/homarr/issues/410)) ([e556bf3](https://github.com/homarr-labs/homarr/commit/e556bf3e6617df664897037cfe6d223e56a8262a)) +* **deps:** update dependency sass to ^1.77.0 ([#451](https://github.com/homarr-labs/homarr/issues/451)) ([3ae96d9](https://github.com/homarr-labs/homarr/commit/3ae96d94a20797f0b4ec5ff22e4649a0fd497748)) +* **deps:** update dependency sass to ^1.77.1 ([#469](https://github.com/homarr-labs/homarr/issues/469)) ([cb6f754](https://github.com/homarr-labs/homarr/commit/cb6f754492b737b70f3db614efd2dfaea49daca9)) +* **deps:** update dependency sass to ^1.77.2 ([#506](https://github.com/homarr-labs/homarr/issues/506)) ([7664b00](https://github.com/homarr-labs/homarr/commit/7664b00be00dd134c130bbb6ffb438155d333553)) +* **deps:** update dependency sass to ^1.77.3 ([#579](https://github.com/homarr-labs/homarr/issues/579)) ([169feca](https://github.com/homarr-labs/homarr/commit/169fecaba1645f0313e730de0e0caff0793cd4c4)) +* **deps:** update dependency sass to ^1.77.4 ([#586](https://github.com/homarr-labs/homarr/issues/586)) ([79d977c](https://github.com/homarr-labs/homarr/commit/79d977c0085e8fc600d1806a566ac17e763dfc48)) +* **deps:** update dependency sass to ^1.77.5 ([#659](https://github.com/homarr-labs/homarr/issues/659)) ([f5f6388](https://github.com/homarr-labs/homarr/commit/f5f63883612c320d4a73cb5bf9435b30c6071537)) +* **deps:** update dependency sass to ^1.77.6 ([#683](https://github.com/homarr-labs/homarr/issues/683)) ([4526fa6](https://github.com/homarr-labs/homarr/commit/4526fa6fc488aad0b54093e47e9064d771473d30)) +* **deps:** update dependency sass to ^1.77.7 ([#773](https://github.com/homarr-labs/homarr/issues/773)) ([dcb9cfa](https://github.com/homarr-labs/homarr/commit/dcb9cfaf295c3aeb30181ea5c7c7e404785e6763)) +* **deps:** update dependency sass to ^1.77.8 ([#783](https://github.com/homarr-labs/homarr/issues/783)) ([ec4b3a6](https://github.com/homarr-labs/homarr/commit/ec4b3a64081bd5d94d4e728dcd7562f708cf0c5f)) +* **deps:** update dependency sass to ^1.78.0 ([#1064](https://github.com/homarr-labs/homarr/issues/1064)) ([3d1b626](https://github.com/homarr-labs/homarr/commit/3d1b626baa736a6a41b4b35f32ef44d948b2f309)) +* **deps:** update dependency sass to ^1.79.0 ([#1147](https://github.com/homarr-labs/homarr/issues/1147)) ([f1d5dd0](https://github.com/homarr-labs/homarr/commit/f1d5dd03cbea8ea569d21f94b95e31d66cb03adc)) +* **deps:** update dependency sass to ^1.79.1 ([#1148](https://github.com/homarr-labs/homarr/issues/1148)) ([3cb1221](https://github.com/homarr-labs/homarr/commit/3cb1221038715ae8d771c3a6622f666ae9493aef)) +* **deps:** update dependency sass to ^1.79.2 ([#1153](https://github.com/homarr-labs/homarr/issues/1153)) ([a028251](https://github.com/homarr-labs/homarr/commit/a02825113a17aa3142ced5a726058bd6168beee1)) +* **deps:** update dependency sass to ^1.79.3 ([#1159](https://github.com/homarr-labs/homarr/issues/1159)) ([612a158](https://github.com/homarr-labs/homarr/commit/612a15810b671cedeb9fefd7902692a466394e3a)) +* **deps:** update dependency sass to ^1.79.4 ([#1198](https://github.com/homarr-labs/homarr/issues/1198)) ([9af01bb](https://github.com/homarr-labs/homarr/commit/9af01bb68006af39f009e4a0605cc0a7f42bcba5)) +* **deps:** update dependency sass to ^1.79.5 ([#1279](https://github.com/homarr-labs/homarr/issues/1279)) ([99ddd92](https://github.com/homarr-labs/homarr/commit/99ddd9214edb8841a1c969af9c1d1f91643e6df8)) +* **deps:** update dependency sass to ^1.79.6 ([#1312](https://github.com/homarr-labs/homarr/issues/1312)) ([0c134dd](https://github.com/homarr-labs/homarr/commit/0c134dde6e9b472cd5cd32dfebdc9146e4fb64db)) +* **deps:** update dependency sass to ^1.80.1 ([#1314](https://github.com/homarr-labs/homarr/issues/1314)) ([a44c907](https://github.com/homarr-labs/homarr/commit/a44c90774547d9ad6c4911c12f21ffa98b3694e5)) +* **deps:** update dependency sass to ^1.80.2 ([#1319](https://github.com/homarr-labs/homarr/issues/1319)) ([3781fe5](https://github.com/homarr-labs/homarr/commit/3781fe5cf876d36aacc7bb4f373ea7973e4e57f7)) +* **deps:** update dependency sass to ^1.80.3 ([#1331](https://github.com/homarr-labs/homarr/issues/1331)) ([e46bf5d](https://github.com/homarr-labs/homarr/commit/e46bf5d24811aa9c8e8092d6635e67f665123721)) +* **deps:** update dependency sass to ^1.80.4 ([#1366](https://github.com/homarr-labs/homarr/issues/1366)) ([2bac28a](https://github.com/homarr-labs/homarr/commit/2bac28a50a843bdf2bdefdc9bad4a07af2fa92b9)) +* **deps:** update dependency sass to ^1.80.5 ([#1388](https://github.com/homarr-labs/homarr/issues/1388)) ([74a8495](https://github.com/homarr-labs/homarr/commit/74a84959034ba1383716e06a7ce73d2f6397e40f)) +* **deps:** update dependency sass to ^1.80.6 ([#1399](https://github.com/homarr-labs/homarr/issues/1399)) ([d908b3f](https://github.com/homarr-labs/homarr/commit/d908b3f6769fe5add91e605f16dc6c5f89d96373)) +* **deps:** update dependency sass to ^1.80.7 ([#1472](https://github.com/homarr-labs/homarr/issues/1472)) ([9bd0e0f](https://github.com/homarr-labs/homarr/commit/9bd0e0f4ee49a3e6ed5245312c5fb77ff8dc48a8)) +* **deps:** update dependency sass to ^1.81.0 ([#1486](https://github.com/homarr-labs/homarr/issues/1486)) ([908d0bb](https://github.com/homarr-labs/homarr/commit/908d0bbc5066e3ee312c89025e3bd60c224094f3)) +* **deps:** update dependency sass to ^1.81.1 ([#1589](https://github.com/homarr-labs/homarr/issues/1589)) ([57bbd43](https://github.com/homarr-labs/homarr/commit/57bbd43c74d29272ac0fa3667965fd78decc4e6b)) +* **deps:** update dependency sass to ^1.82.0 ([#1600](https://github.com/homarr-labs/homarr/issues/1600)) ([825b1a3](https://github.com/homarr-labs/homarr/commit/825b1a3643266049ddf5a6cd53defa47e78d8cc8)) +* **deps:** update dependency sass to ^1.83.0 ([#1650](https://github.com/homarr-labs/homarr/issues/1650)) ([0bd8e2c](https://github.com/homarr-labs/homarr/commit/0bd8e2c08516fabd9bd6c3d4649abb4f47d7bc13)) +* **deps:** update dependency sharp to ^0.33.3 ([#260](https://github.com/homarr-labs/homarr/issues/260)) ([87808c1](https://github.com/homarr-labs/homarr/commit/87808c1349f520a4d2160a11ef49c11a91665ea9)) +* **deps:** update dependency superjson to v2.2.2 ([#1618](https://github.com/homarr-labs/homarr/issues/1618)) ([aaa3e7c](https://github.com/homarr-labs/homarr/commit/aaa3e7ce0c58f644db283e5c256779b5c4fb09bb)) +* **deps:** update dependency swagger-ui-react to ^5.17.14 ([#1031](https://github.com/homarr-labs/homarr/issues/1031)) ([6351bf7](https://github.com/homarr-labs/homarr/commit/6351bf78ff902948218b50d568e7d7425a27b2ad)) +* **deps:** update dependency swagger-ui-react to ^5.18.0 ([#1428](https://github.com/homarr-labs/homarr/issues/1428)) ([4643c0f](https://github.com/homarr-labs/homarr/commit/4643c0f004425f54d96871755aec1e0a6cfa30b2)) +* **deps:** update dependency swagger-ui-react to ^5.18.1 ([#1432](https://github.com/homarr-labs/homarr/issues/1432)) ([0809d5a](https://github.com/homarr-labs/homarr/commit/0809d5aa747e4937ca1890ee04972b99e87f26bc)) +* **deps:** update dependency swagger-ui-react to ^5.18.2 ([#1442](https://github.com/homarr-labs/homarr/issues/1442)) ([2357435](https://github.com/homarr-labs/homarr/commit/23574359f0ed180d512810773b48bd046139ae66)) +* **deps:** update dependency tldts to ^6.1.38 ([#931](https://github.com/homarr-labs/homarr/issues/931)) ([a2be781](https://github.com/homarr-labs/homarr/commit/a2be781f81465b32543b28dee7df8f1b0290f12a)) +* **deps:** update dependency tldts to ^6.1.39 ([#966](https://github.com/homarr-labs/homarr/issues/966)) ([4b39c16](https://github.com/homarr-labs/homarr/commit/4b39c16d256656998ab817f58cdaf13fe81dc044)) +* **deps:** update dependency tldts to ^6.1.40 ([#996](https://github.com/homarr-labs/homarr/issues/996)) ([f5c380f](https://github.com/homarr-labs/homarr/commit/f5c380f75b30bc45573a4aaef7fe926c3a71011d)) +* **deps:** update dependency tldts to ^6.1.41 ([#1011](https://github.com/homarr-labs/homarr/issues/1011)) ([7742d5f](https://github.com/homarr-labs/homarr/commit/7742d5f5b4b37ab2fb1e6cdc6a5c25c5caca1a5d)) +* **deps:** update dependency tldts to ^6.1.42 ([#1069](https://github.com/homarr-labs/homarr/issues/1069)) ([247de55](https://github.com/homarr-labs/homarr/commit/247de555cec15ae8f6fac0fd5b2abc90382b1786)) +* **deps:** update dependency tldts to ^6.1.43 ([#1080](https://github.com/homarr-labs/homarr/issues/1080)) ([fc1bff2](https://github.com/homarr-labs/homarr/commit/fc1bff2110e1a4c1fa1d48ba4a42ee4d3ad5b469)) +* **deps:** update dependency tldts to ^6.1.44 ([#1095](https://github.com/homarr-labs/homarr/issues/1095)) ([18347fe](https://github.com/homarr-labs/homarr/commit/18347fef3bc355d42e902e76e0caf02ee855df9a)) +* **deps:** update dependency tldts to ^6.1.45 ([#1121](https://github.com/homarr-labs/homarr/issues/1121)) ([7059a3d](https://github.com/homarr-labs/homarr/commit/7059a3d88f73ddceb70d037bb0f362fe50bda225)) +* **deps:** update dependency tldts to ^6.1.46 ([#1128](https://github.com/homarr-labs/homarr/issues/1128)) ([aca5c27](https://github.com/homarr-labs/homarr/commit/aca5c279b5360fdacd3f5dc77fd58ce41c343e5f)) +* **deps:** update dependency tldts to ^6.1.47 ([#1152](https://github.com/homarr-labs/homarr/issues/1152)) ([aa2d440](https://github.com/homarr-labs/homarr/commit/aa2d440acbbe92d088b9ba9bdf2ebbc5b2b642c1)) +* **deps:** update dependency tldts to ^6.1.48 ([#1190](https://github.com/homarr-labs/homarr/issues/1190)) ([f6c7271](https://github.com/homarr-labs/homarr/commit/f6c7271fb43324f7e9eb0f8cc7ae5646f516b8b2)) +* **deps:** update dependency tldts to ^6.1.49 ([#1216](https://github.com/homarr-labs/homarr/issues/1216)) ([2f3619b](https://github.com/homarr-labs/homarr/commit/2f3619b68dc9f3c20a229b896f8b3c4b91e5c0a7)) +* **deps:** update dependency tldts to ^6.1.50 ([#1228](https://github.com/homarr-labs/homarr/issues/1228)) ([17572bc](https://github.com/homarr-labs/homarr/commit/17572bc602a7b1e42def413f1a7668cf1280170b)) +* **deps:** update dependency tldts to ^6.1.51 ([#1288](https://github.com/homarr-labs/homarr/issues/1288)) ([0fadc28](https://github.com/homarr-labs/homarr/commit/0fadc28a125aa68e6d6d96a17c7c86012d13a288)) +* **deps:** update dependency tldts to ^6.1.52 ([#1307](https://github.com/homarr-labs/homarr/issues/1307)) ([c4ec4f3](https://github.com/homarr-labs/homarr/commit/c4ec4f3c66078b0c94bb049334e32e31e41936ac)) +* **deps:** update dependency tldts to ^6.1.53 ([#1351](https://github.com/homarr-labs/homarr/issues/1351)) ([a8c36f3](https://github.com/homarr-labs/homarr/commit/a8c36f35c3e5a9342fe932832342f76855c8d4d4)) +* **deps:** update dependency tldts to ^6.1.54 ([#1353](https://github.com/homarr-labs/homarr/issues/1353)) ([e062ea1](https://github.com/homarr-labs/homarr/commit/e062ea150782b73d0a86748fef43355a46df2244)) +* **deps:** update dependency tldts to ^6.1.55 ([#1369](https://github.com/homarr-labs/homarr/issues/1369)) ([3a6e957](https://github.com/homarr-labs/homarr/commit/3a6e957710c08e64cc7b42ecca2bf5069cceb896)) +* **deps:** update dependency tldts to ^6.1.56 ([#1375](https://github.com/homarr-labs/homarr/issues/1375)) ([f8c21f6](https://github.com/homarr-labs/homarr/commit/f8c21f6000e8d8843e43afaf09713f958b318f0f)) +* **deps:** update dependency tldts to ^6.1.57 ([#1386](https://github.com/homarr-labs/homarr/issues/1386)) ([8da1dd0](https://github.com/homarr-labs/homarr/commit/8da1dd0d5f95e1d15f1115a8518992935e89059c)) +* **deps:** update dependency tldts to ^6.1.58 ([#1400](https://github.com/homarr-labs/homarr/issues/1400)) ([baabf71](https://github.com/homarr-labs/homarr/commit/baabf717078caba315f39a1d429fc0ba92f3d167)) +* **deps:** update dependency tldts to ^6.1.59 ([#1447](https://github.com/homarr-labs/homarr/issues/1447)) ([2a7d648](https://github.com/homarr-labs/homarr/commit/2a7d64804975797863b9a4a7b03d7ab10f4d8a2b)) +* **deps:** update dependency tldts to ^6.1.60 ([#1460](https://github.com/homarr-labs/homarr/issues/1460)) ([4ab40c6](https://github.com/homarr-labs/homarr/commit/4ab40c6fa8e13af66a0a3b14e3c03955ff98f2c7)) +* **deps:** update dependency tldts to ^6.1.61 ([#1474](https://github.com/homarr-labs/homarr/issues/1474)) ([3ca97fe](https://github.com/homarr-labs/homarr/commit/3ca97fef0b984e06461d92f16564bd787ff53150)) +* **deps:** update dependency tldts to ^6.1.62 ([#1514](https://github.com/homarr-labs/homarr/issues/1514)) ([a2a65ab](https://github.com/homarr-labs/homarr/commit/a2a65abd3d451104d59e8eb55ad74d83f6956784)) +* **deps:** update dependency tldts to ^6.1.63 ([#1519](https://github.com/homarr-labs/homarr/issues/1519)) ([86ae346](https://github.com/homarr-labs/homarr/commit/86ae3469795378f626a2b6aa5eaaf6cd38c874d9)) +* **deps:** update dependency tldts to ^6.1.64 ([#1529](https://github.com/homarr-labs/homarr/issues/1529)) ([cdfb61f](https://github.com/homarr-labs/homarr/commit/cdfb61fb28f6a9adc8658187a41e0cfb3fdc1a8f)) +* **deps:** update dependency tldts to ^6.1.65 ([#1575](https://github.com/homarr-labs/homarr/issues/1575)) ([fb4a19b](https://github.com/homarr-labs/homarr/commit/fb4a19bfe457d1d815e9b72a85c8ea742b950a69)) +* **deps:** update dependency tldts to ^6.1.66 ([#1625](https://github.com/homarr-labs/homarr/issues/1625)) ([6a79d01](https://github.com/homarr-labs/homarr/commit/6a79d01d79b613dccf2a3ffe39a7271bc1931812)) +* **deps:** update dependency tldts to ^6.1.67 ([#1648](https://github.com/homarr-labs/homarr/issues/1648)) ([75c0f70](https://github.com/homarr-labs/homarr/commit/75c0f70ef6159bbada6770a49cfba59f4470fcfc)) +* **deps:** update dependency tldts to ^6.1.68 ([#1656](https://github.com/homarr-labs/homarr/issues/1656)) ([3347886](https://github.com/homarr-labs/homarr/commit/3347886f1e6754f9dd0f8a9975c51bf61b0d3f59)) +* **deps:** update dependency trpc-swagger to ^1.2.6 ([#1032](https://github.com/homarr-labs/homarr/issues/1032)) ([e60e4a4](https://github.com/homarr-labs/homarr/commit/e60e4a49f84ec46f47bdaa830cea5ddeaf7ba8a3)) +* **deps:** update dependency trpc-to-openapi to ^2.0.3 ([#1576](https://github.com/homarr-labs/homarr/issues/1576)) ([0ab9d0b](https://github.com/homarr-labs/homarr/commit/0ab9d0bd694d2cb66de45bcfd0010ecc2b226cb7)) +* **deps:** update dependency trpc-to-openapi to ^2.0.4 ([#1578](https://github.com/homarr-labs/homarr/issues/1578)) ([3ffdc05](https://github.com/homarr-labs/homarr/commit/3ffdc054429a6ec6a3ddc14b9d1ac97602eb0f15)) +* **deps:** update dependency trpc-to-openapi to ^2.1.0 ([#1579](https://github.com/homarr-labs/homarr/issues/1579)) ([7343bdd](https://github.com/homarr-labs/homarr/commit/7343bdde1304f655149c257319996047ddd8a530)) +* **deps:** update dependency typescript-eslint to ^7.13.0 ([#653](https://github.com/homarr-labs/homarr/issues/653)) ([1949885](https://github.com/homarr-labs/homarr/commit/19498854fc1da6fdb9ec29f3ecb7a113a6b2a33e)) +* **deps:** update dependency typescript-eslint to ^7.13.1 ([#681](https://github.com/homarr-labs/homarr/issues/681)) ([e9d6120](https://github.com/homarr-labs/homarr/commit/e9d612051d043253d7c41bafdd4be82949564e43)) +* **deps:** update dependency typescript-eslint to ^7.14.1 ([#709](https://github.com/homarr-labs/homarr/issues/709)) ([196ac34](https://github.com/homarr-labs/homarr/commit/196ac340a16528196e1ca405147c83ed31f8337a)) +* **deps:** update dependency typescript-eslint to ^7.15.0 ([#732](https://github.com/homarr-labs/homarr/issues/732)) ([0990e4b](https://github.com/homarr-labs/homarr/commit/0990e4b552e3c65ee8802e11d2bd3adceab24009)) +* **deps:** update dependency typescript-eslint to ^7.16.0 ([#762](https://github.com/homarr-labs/homarr/issues/762)) ([2c197bc](https://github.com/homarr-labs/homarr/commit/2c197bc59bab428db4990a7c99b1dcdd8b372617)) +* **deps:** update dependency typescript-eslint to ^7.16.1 ([#814](https://github.com/homarr-labs/homarr/issues/814)) ([56c6be5](https://github.com/homarr-labs/homarr/commit/56c6be523db5219b97bafbc53d63360d019fefcc)) +* **deps:** update dependency typescript-eslint to ^7.17.0 ([#855](https://github.com/homarr-labs/homarr/issues/855)) ([b2860ff](https://github.com/homarr-labs/homarr/commit/b2860ffbd3e29ef21021b2416d0c26f0e3b6c54c)) +* **deps:** update dependency typescript-eslint to ^7.18.0 ([#886](https://github.com/homarr-labs/homarr/issues/886)) ([1a24ba6](https://github.com/homarr-labs/homarr/commit/1a24ba6ef73eb058f19f31140cff5198311eba08)) +* **deps:** update dependency typescript-eslint to ^8.0.1 ([#921](https://github.com/homarr-labs/homarr/issues/921)) ([c69483a](https://github.com/homarr-labs/homarr/commit/c69483a12c14ab284dd3cacd0e31d194dcc48cfc)) +* **deps:** update dependency typescript-eslint to ^8.1.0 ([#968](https://github.com/homarr-labs/homarr/issues/968)) ([b9f048c](https://github.com/homarr-labs/homarr/commit/b9f048c57d9f2618f8059862a800259246caa2f8)) +* **deps:** update dependency typescript-eslint to ^8.10.0 ([#1317](https://github.com/homarr-labs/homarr/issues/1317)) ([a231a2d](https://github.com/homarr-labs/homarr/commit/a231a2da6cd42e355fff52b9cf718f44c658cfff)) +* **deps:** update dependency typescript-eslint to ^8.11.0 ([#1346](https://github.com/homarr-labs/homarr/issues/1346)) ([a005ead](https://github.com/homarr-labs/homarr/commit/a005ead158ca1f058605b2a3198af438c7039109)) +* **deps:** update dependency typescript-eslint to ^8.12.2 ([#1381](https://github.com/homarr-labs/homarr/issues/1381)) ([17401d1](https://github.com/homarr-labs/homarr/commit/17401d1d7284088bc5fdc0e037dc72f75e8abd7e)) +* **deps:** update dependency typescript-eslint to ^8.13.0 ([#1420](https://github.com/homarr-labs/homarr/issues/1420)) ([97eb4c5](https://github.com/homarr-labs/homarr/commit/97eb4c54e2f7f9cfc0467b0236b4a2db87bc546c)) +* **deps:** update dependency typescript-eslint to ^8.14.0 ([#1465](https://github.com/homarr-labs/homarr/issues/1465)) ([53acff9](https://github.com/homarr-labs/homarr/commit/53acff91430b9889c90ab9e1a35bce792baa4dd9)) +* **deps:** update dependency typescript-eslint to ^8.15.0 ([#1497](https://github.com/homarr-labs/homarr/issues/1497)) ([b887713](https://github.com/homarr-labs/homarr/commit/b8877137ac05a08c5647d0ba785439d364d9bafb)) +* **deps:** update dependency typescript-eslint to ^8.16.0 ([#1544](https://github.com/homarr-labs/homarr/issues/1544)) ([4df6006](https://github.com/homarr-labs/homarr/commit/4df6006f0e487028fffc3f65d4fa20b2f252e612)) +* **deps:** update dependency typescript-eslint to ^8.17.0 ([#1582](https://github.com/homarr-labs/homarr/issues/1582)) ([5ecf93a](https://github.com/homarr-labs/homarr/commit/5ecf93a317f8face4d47d255c83c7f197eccdb92)) +* **deps:** update dependency typescript-eslint to ^8.18.0 ([#1634](https://github.com/homarr-labs/homarr/issues/1634)) ([3bee3fe](https://github.com/homarr-labs/homarr/commit/3bee3fe3f64c274c73f698cd5f8850f4496c35bd)) +* **deps:** update dependency typescript-eslint to ^8.18.1 ([#1673](https://github.com/homarr-labs/homarr/issues/1673)) ([613d1f9](https://github.com/homarr-labs/homarr/commit/613d1f966282886c6a85bc400dfedbc4bdac906c)) +* **deps:** update dependency typescript-eslint to ^8.2.0 ([#999](https://github.com/homarr-labs/homarr/issues/999)) ([0585187](https://github.com/homarr-labs/homarr/commit/058518710e02ea47bc6e221cab43604d70b16ab5)) +* **deps:** update dependency typescript-eslint to ^8.3.0 ([#1036](https://github.com/homarr-labs/homarr/issues/1036)) ([b0e2692](https://github.com/homarr-labs/homarr/commit/b0e269209e67db1569effd72d1560c0414574654)) +* **deps:** update dependency typescript-eslint to ^8.4.0 ([#1058](https://github.com/homarr-labs/homarr/issues/1058)) ([1d23667](https://github.com/homarr-labs/homarr/commit/1d236678b334c35358a3d95e75d81ad16657afca)) +* **deps:** update dependency typescript-eslint to ^8.5.0 ([#1089](https://github.com/homarr-labs/homarr/issues/1089)) ([c844eb2](https://github.com/homarr-labs/homarr/commit/c844eb2a224c473dd42df4a1ffc9a74bd533e0e2)) +* **deps:** update dependency typescript-eslint to ^8.6.0 ([#1136](https://github.com/homarr-labs/homarr/issues/1136)) ([3ef478c](https://github.com/homarr-labs/homarr/commit/3ef478c53ab56c50b1ee1d71eebfcc32a4b8828a)) +* **deps:** update dependency typescript-eslint to ^8.7.0 ([#1165](https://github.com/homarr-labs/homarr/issues/1165)) ([6aa5adf](https://github.com/homarr-labs/homarr/commit/6aa5adf5b0602dc3c7de75d9fc88c751d77ceed9)) +* **deps:** update dependency typescript-eslint to ^8.8.0 ([#1207](https://github.com/homarr-labs/homarr/issues/1207)) ([233033f](https://github.com/homarr-labs/homarr/commit/233033f1ce2c1348287fd4f37cf27e53ca317868)) +* **deps:** update dependency typescript-eslint to ^8.8.1 ([#1266](https://github.com/homarr-labs/homarr/issues/1266)) ([4d51e3b](https://github.com/homarr-labs/homarr/commit/4d51e3b3442860fa43ef2766681aaf2bce771d3f)) +* **deps:** update dependency typescript-eslint to ^8.9.0 ([#1292](https://github.com/homarr-labs/homarr/issues/1292)) ([65b1ae2](https://github.com/homarr-labs/homarr/commit/65b1ae26d15d29820f3feb097f6ccf43e89b5e22)) +* **deps:** update dependency typescript-eslint to v8 ([#896](https://github.com/homarr-labs/homarr/issues/896)) ([a9a4602](https://github.com/homarr-labs/homarr/commit/a9a46024e2a1a130bf0f2d9f87d1fa7caa35823b)) +* **deps:** update dependency undici to v6.19.2 ([#691](https://github.com/homarr-labs/homarr/issues/691)) ([541d745](https://github.com/homarr-labs/homarr/commit/541d745cea4d615d88f0af454e39de61cfa104cf)) +* **deps:** update dependency undici to v6.19.3 ([#850](https://github.com/homarr-labs/homarr/issues/850)) ([1098725](https://github.com/homarr-labs/homarr/commit/1098725bd1f010056e40eb00db40e19011ef158a)) +* **deps:** update dependency undici to v6.19.4 ([#854](https://github.com/homarr-labs/homarr/issues/854)) ([0c7264b](https://github.com/homarr-labs/homarr/commit/0c7264bc52c80794a74c9836ae9f9d56df6fc52c)) +* **deps:** update dependency undici to v6.19.5 ([#893](https://github.com/homarr-labs/homarr/issues/893)) ([5256853](https://github.com/homarr-labs/homarr/commit/525685335103289eb06606b04610dcec1ecbf0a1)) +* **deps:** update dependency undici to v6.19.7 ([#950](https://github.com/homarr-labs/homarr/issues/950)) ([3be1100](https://github.com/homarr-labs/homarr/commit/3be110097bcb500ef79d88b28b626bcf15329ed3)) +* **deps:** update dependency undici to v6.19.8 ([#998](https://github.com/homarr-labs/homarr/issues/998)) ([9666440](https://github.com/homarr-labs/homarr/commit/9666440e803ce2275ef3d90ebbc37c00592b8372)) +* **deps:** update dependency undici to v6.20.0 ([#1275](https://github.com/homarr-labs/homarr/issues/1275)) ([c7b2261](https://github.com/homarr-labs/homarr/commit/c7b226142feaa3fb0651cdf8473d714643e8144d)) +* **deps:** update dependency undici to v6.20.1 ([#1291](https://github.com/homarr-labs/homarr/issues/1291)) ([85cf101](https://github.com/homarr-labs/homarr/commit/85cf101043a7dbcd9b3a956eb8b7fffb6d3712e3)) +* **deps:** update dependency undici to v6.21.0 ([#1477](https://github.com/homarr-labs/homarr/issues/1477)) ([07f89af](https://github.com/homarr-labs/homarr/commit/07f89afea8eb47894c1ef94e8f62f8fb8c45ebe8)) +* **deps:** update dependency undici to v7 ([#1560](https://github.com/homarr-labs/homarr/issues/1560)) ([44e2105](https://github.com/homarr-labs/homarr/commit/44e2105a8c9d7cc746f0424bf1f718f426dbea93)) +* **deps:** update dependency undici to v7.1.0 ([#1593](https://github.com/homarr-labs/homarr/issues/1593)) ([fb1f000](https://github.com/homarr-labs/homarr/commit/fb1f0003e60d21713968bc6ff4ec1ce85bc54388)) +* **deps:** update dependency undici to v7.1.1 ([#1674](https://github.com/homarr-labs/homarr/issues/1674)) ([02777d1](https://github.com/homarr-labs/homarr/commit/02777d104c5da555337b3b1494a906488fcc7d64)) +* **deps:** update dependency video.js to ^8.12.0 ([#400](https://github.com/homarr-labs/homarr/issues/400)) ([fc1360d](https://github.com/homarr-labs/homarr/commit/fc1360d6bb9512be8ca1f91e8624d2b9b45d1175)) +* **deps:** update dependency video.js to ^8.16.1 ([#772](https://github.com/homarr-labs/homarr/issues/772)) ([8085e72](https://github.com/homarr-labs/homarr/commit/8085e72cf487a1a757bd07f85f46280f2e677f9f)) +* **deps:** update dependency video.js to ^8.17.1 ([#884](https://github.com/homarr-labs/homarr/issues/884)) ([bce73bc](https://github.com/homarr-labs/homarr/commit/bce73bc38f19b5382f0ab233eac667dd926c27a3)) +* **deps:** update dependency video.js to ^8.17.2 ([#917](https://github.com/homarr-labs/homarr/issues/917)) ([796261c](https://github.com/homarr-labs/homarr/commit/796261c5f5f1fa2b02ce3d9ef338a5196d90ec07)) +* **deps:** update dependency video.js to ^8.17.3 ([#971](https://github.com/homarr-labs/homarr/issues/971)) ([0472594](https://github.com/homarr-labs/homarr/commit/04725942eeca3e4c535c6773044eea1b2dc68a33)) +* **deps:** update dependency video.js to ^8.17.4 ([#1099](https://github.com/homarr-labs/homarr/issues/1099)) ([8c9bb6e](https://github.com/homarr-labs/homarr/commit/8c9bb6e5d5eb61f5f7d60aa38c44c94675ab8202)) +* **deps:** update dependency video.js to ^8.18.1 ([#1259](https://github.com/homarr-labs/homarr/issues/1259)) ([ea84b1c](https://github.com/homarr-labs/homarr/commit/ea84b1c372efc40c4c48bf18347c734291a95997)) +* **deps:** update dependency video.js to ^8.19.1 ([#1370](https://github.com/homarr-labs/homarr/issues/1370)) ([4985bd8](https://github.com/homarr-labs/homarr/commit/4985bd8f9123b629dc9bba3c6bb40eaeab96cf87)) +* **deps:** update dependency video.js to ^8.20.0 ([#1561](https://github.com/homarr-labs/homarr/issues/1561)) ([9f98290](https://github.com/homarr-labs/homarr/commit/9f982906f25b042443ac57e8a46ccf98aca5731d)) +* **deps:** update dependency video.js to ^8.21.0 ([#1617](https://github.com/homarr-labs/homarr/issues/1617)) ([5c11a95](https://github.com/homarr-labs/homarr/commit/5c11a95ddcb8e31fbb1c1156a24a89f04f7c22b1)) +* **deps:** update dependency vite to ^5.2.3 ([#253](https://github.com/homarr-labs/homarr/issues/253)) ([7214df3](https://github.com/homarr-labs/homarr/commit/7214df3e442bb8dfc588b1470ed5cef89636643e)) +* **deps:** update dependency vite to ^5.2.5 ([#259](https://github.com/homarr-labs/homarr/issues/259)) ([8d40f54](https://github.com/homarr-labs/homarr/commit/8d40f54d7d1e350f1cd274de493fbe003eee2641)) +* **deps:** update dependency vite to ^5.2.6 ([#262](https://github.com/homarr-labs/homarr/issues/262)) ([36073db](https://github.com/homarr-labs/homarr/commit/36073dbc5ee404379e8ad165a53c2f703642b07a)) +* **deps:** update dependency winston to v3.12.0 ([#188](https://github.com/homarr-labs/homarr/issues/188)) ([fde6d66](https://github.com/homarr-labs/homarr/commit/fde6d6601d8a19b95896ccd8cd9654c48b1f6c48)) +* **deps:** update dependency winston to v3.13.0 ([#263](https://github.com/homarr-labs/homarr/issues/263)) ([724b348](https://github.com/homarr-labs/homarr/commit/724b3481063c028465af08127fb419b0551bb455)) +* **deps:** update dependency winston to v3.13.1 ([#781](https://github.com/homarr-labs/homarr/issues/781)) ([5382b19](https://github.com/homarr-labs/homarr/commit/5382b1999fd3d6ec3e6e043fbde5bd68a93f0e2d)) +* **deps:** update dependency winston to v3.14.0 ([#935](https://github.com/homarr-labs/homarr/issues/935)) ([ac4b4ed](https://github.com/homarr-labs/homarr/commit/ac4b4ed9cf5fc815dd83dce5e3f9608b4aac07af)) +* **deps:** update dependency winston to v3.14.1 ([#941](https://github.com/homarr-labs/homarr/issues/941)) ([db9c200](https://github.com/homarr-labs/homarr/commit/db9c200f890c70be6163b451e30f8950b676c2a1)) +* **deps:** update dependency winston to v3.14.2 ([#979](https://github.com/homarr-labs/homarr/issues/979)) ([b9bcc1d](https://github.com/homarr-labs/homarr/commit/b9bcc1d23aa20bf665c0fb13ec14f8eed0f6516e)) +* **deps:** update dependency winston to v3.15.0 ([#1245](https://github.com/homarr-labs/homarr/issues/1245)) ([20e6399](https://github.com/homarr-labs/homarr/commit/20e6399d5e493158b7c0fb9370e9287075d315da)) +* **deps:** update dependency winston to v3.16.0 ([#1398](https://github.com/homarr-labs/homarr/issues/1398)) ([02ddb1c](https://github.com/homarr-labs/homarr/commit/02ddb1c9c6d15e4965c93935ff7887f90bff05a4)) +* **deps:** update dependency winston to v3.17.0 ([#1457](https://github.com/homarr-labs/homarr/issues/1457)) ([fc4cddc](https://github.com/homarr-labs/homarr/commit/fc4cddcbac74122e652d5409c875694ae11dc78a)) +* **deps:** update dependency ws to ^8.17.0 ([#392](https://github.com/homarr-labs/homarr/issues/392)) ([55822ee](https://github.com/homarr-labs/homarr/commit/55822ee7a51b4f907ed5be3b8202c60d07dce506)) +* **deps:** update dependency ws to ^8.17.1 ([#676](https://github.com/homarr-labs/homarr/issues/676)) ([0d14bad](https://github.com/homarr-labs/homarr/commit/0d14bad10bc45b50e0d3551c071f1ec62c9b7403)) +* **deps:** update dependency ws to ^8.18.0 ([#740](https://github.com/homarr-labs/homarr/issues/740)) ([1dd509a](https://github.com/homarr-labs/homarr/commit/1dd509a40fb9090ba88a0d8e1a67baf58b244cd9)) +* **deps:** update dependency zod to ^3.22.5 ([#361](https://github.com/homarr-labs/homarr/issues/361)) ([cb2b934](https://github.com/homarr-labs/homarr/commit/cb2b934c83c3464ff71bd9dff3be9742e975ef8c)) +* **deps:** update dependency zod to ^3.23.4 ([#373](https://github.com/homarr-labs/homarr/issues/373)) ([392a185](https://github.com/homarr-labs/homarr/commit/392a18564045ab2ea68c694192f771234e40b90c)) +* **deps:** update dependency zod to ^3.23.5 ([#399](https://github.com/homarr-labs/homarr/issues/399)) ([56388eb](https://github.com/homarr-labs/homarr/commit/56388eb8ef452e1dae0ca9c0c68ed6a2ff6fbbd1)) +* **deps:** update dependency zod to ^3.23.6 ([#424](https://github.com/homarr-labs/homarr/issues/424)) ([11c20ce](https://github.com/homarr-labs/homarr/commit/11c20ce711e564bc76d835ed839dbe7dfe332301)) +* **deps:** update dependency zod to ^3.23.7 ([#456](https://github.com/homarr-labs/homarr/issues/456)) ([cab3405](https://github.com/homarr-labs/homarr/commit/cab34052f905d22f5ee593a960895cc9c137292c)) +* **deps:** update dependency zod to ^3.23.8 ([#460](https://github.com/homarr-labs/homarr/issues/460)) ([687556a](https://github.com/homarr-labs/homarr/commit/687556ad96136a72dc720a38f4628d0ba5a1cbcb)) +* **deps:** update dependency zod to ^3.24.0 ([#1635](https://github.com/homarr-labs/homarr/issues/1635)) ([8a25467](https://github.com/homarr-labs/homarr/commit/8a2546704b56d35786681fa6924770b04f833dff)) +* **deps:** update dependency zod to ^3.24.1 ([#1642](https://github.com/homarr-labs/homarr/issues/1642)) ([5e466e8](https://github.com/homarr-labs/homarr/commit/5e466e80c54accbc303e44d2093518465ad5863e)) +* **deps:** update gridstack.js fork to v1.11.2 ([#1605](https://github.com/homarr-labs/homarr/issues/1605)) ([bf45860](https://github.com/homarr-labs/homarr/commit/bf45860966987be44c5eecf9add34173f5968194)) +* **deps:** update mantine monorepo to ^7.10.0 ([#538](https://github.com/homarr-labs/homarr/issues/538)) ([ad3ef4c](https://github.com/homarr-labs/homarr/commit/ad3ef4c313fceb40baaedb9bc3b0e17009eed5cb)) +* **deps:** update mantine monorepo to ^7.10.1 ([#581](https://github.com/homarr-labs/homarr/issues/581)) ([b12d109](https://github.com/homarr-labs/homarr/commit/b12d109f6dfa4f90fc9fe2fae216894d601d0594)) +* **deps:** update mantine monorepo to ^7.10.2 ([#662](https://github.com/homarr-labs/homarr/issues/662)) ([4e9593b](https://github.com/homarr-labs/homarr/commit/4e9593b859c2d16e89940de9abed418ae184f36f)) +* **deps:** update mantine monorepo to ^7.11.0 ([#719](https://github.com/homarr-labs/homarr/issues/719)) ([52e936f](https://github.com/homarr-labs/homarr/commit/52e936f979b9cb6968c6cfe3a66c2c652245c6d8)) +* **deps:** update mantine monorepo to ^7.11.1 ([#735](https://github.com/homarr-labs/homarr/issues/735)) ([60c0cfa](https://github.com/homarr-labs/homarr/commit/60c0cfa9119ae946ca232df00dcebf73c3259a00)) +* **deps:** update mantine monorepo to ^7.11.2 ([#808](https://github.com/homarr-labs/homarr/issues/808)) ([fe5af92](https://github.com/homarr-labs/homarr/commit/fe5af9231e0c8e604558056e28ddc0ad5d440ad8)) +* **deps:** update mantine monorepo to ^7.12.0 ([#920](https://github.com/homarr-labs/homarr/issues/920)) ([137ebf6](https://github.com/homarr-labs/homarr/commit/137ebf6d22bc1a420bab52444e2cd3df5fe31852)) +* **deps:** update mantine monorepo to ^7.12.1 ([#967](https://github.com/homarr-labs/homarr/issues/967)) ([5b651a7](https://github.com/homarr-labs/homarr/commit/5b651a782aef6ce6ecef58be0491642d4cf0c94f)) +* **deps:** update mantine monorepo to ^7.12.2 ([#1048](https://github.com/homarr-labs/homarr/issues/1048)) ([51be024](https://github.com/homarr-labs/homarr/commit/51be02477b63725f5052d478a6db59c48be1fdf0)) +* **deps:** update mantine monorepo to ^7.13.0 ([#1178](https://github.com/homarr-labs/homarr/issues/1178)) ([78230b1](https://github.com/homarr-labs/homarr/commit/78230b1fe9d4b5b071d80782f6ad177993903dd1)) +* **deps:** update mantine monorepo to ^7.13.1 ([#1205](https://github.com/homarr-labs/homarr/issues/1205)) ([6ce466d](https://github.com/homarr-labs/homarr/commit/6ce466d38ec8d3968c4f90583cdfd83d97a42154)) +* **deps:** update mantine monorepo to ^7.13.2 ([#1227](https://github.com/homarr-labs/homarr/issues/1227)) ([d383664](https://github.com/homarr-labs/homarr/commit/d3836648c288ca595ac7b43cc1a2089cd52b7cdd)) +* **deps:** update mantine monorepo to ^7.13.3 ([#1316](https://github.com/homarr-labs/homarr/issues/1316)) ([84bb1de](https://github.com/homarr-labs/homarr/commit/84bb1deae51982d5c7465b180198034c9f9b861a)) +* **deps:** update mantine monorepo to ^7.13.4 ([#1364](https://github.com/homarr-labs/homarr/issues/1364)) ([f55b813](https://github.com/homarr-labs/homarr/commit/f55b813aa1a1df8c1b5c0f29a9a302dab025a1aa)) +* **deps:** update mantine monorepo to ^7.13.5 ([#1449](https://github.com/homarr-labs/homarr/issues/1449)) ([2306ecd](https://github.com/homarr-labs/homarr/commit/2306ecda9f562e94ef21eae495eab4e7fc5a3fc2)) +* **deps:** update mantine monorepo to ^7.14.0 ([#1470](https://github.com/homarr-labs/homarr/issues/1470)) ([11ce6fa](https://github.com/homarr-labs/homarr/commit/11ce6faa37bcd6c54f348ed8c5d003ff4c061b40)) +* **deps:** update mantine monorepo to ^7.14.1 ([#1494](https://github.com/homarr-labs/homarr/issues/1494)) ([775d0a5](https://github.com/homarr-labs/homarr/commit/775d0a53decfbebdbab06936557adade378fd0c0)) +* **deps:** update mantine monorepo to ^7.14.2 ([#1537](https://github.com/homarr-labs/homarr/issues/1537)) ([2e28147](https://github.com/homarr-labs/homarr/commit/2e2814707e0a5c2c38ccefcf0387cc0dab195fb9)) +* **deps:** update mantine monorepo to ^7.14.3 ([#1563](https://github.com/homarr-labs/homarr/issues/1563)) ([09dae45](https://github.com/homarr-labs/homarr/commit/09dae45ae8c33cf9212b72b7b048bbb3866880eb)) +* **deps:** update mantine monorepo to ^7.15.0 ([#1636](https://github.com/homarr-labs/homarr/issues/1636)) ([99bb680](https://github.com/homarr-labs/homarr/commit/99bb68012faffa78e9eb279dcf57007250a7a343)) +* **deps:** update mantine monorepo to ^7.15.1 ([#1649](https://github.com/homarr-labs/homarr/issues/1649)) ([732f4d4](https://github.com/homarr-labs/homarr/commit/732f4d45bdc1a063640a4636de4b67f25927fe43)) +* **deps:** update mantine monorepo to ^7.5.2 ([#71](https://github.com/homarr-labs/homarr/issues/71)) ([81e61b4](https://github.com/homarr-labs/homarr/commit/81e61b4d6bea3f32822917c4cf03f4d5876397ca)) +* **deps:** update mantine monorepo to ^7.5.3 ([#97](https://github.com/homarr-labs/homarr/issues/97)) ([35edfc7](https://github.com/homarr-labs/homarr/commit/35edfc74c4000d59b72f58fb42a00093151d4f38)) +* **deps:** update mantine monorepo to ^7.6.1 ([#157](https://github.com/homarr-labs/homarr/issues/157)) ([8c0534f](https://github.com/homarr-labs/homarr/commit/8c0534f54c416af94743e1cf20d92a33e06c804c)) +* **deps:** update mantine monorepo to ^7.6.2 ([#221](https://github.com/homarr-labs/homarr/issues/221)) ([fc29db0](https://github.com/homarr-labs/homarr/commit/fc29db0151de2638d7550dad0a8328b87164a732)) +* **deps:** update mantine monorepo to ^7.7.1 ([#272](https://github.com/homarr-labs/homarr/issues/272)) ([c9e1580](https://github.com/homarr-labs/homarr/commit/c9e15805a9b4c845e5cc379ae8267c7c659c60a6)) +* **deps:** update mantine monorepo to ^7.8.0 ([#343](https://github.com/homarr-labs/homarr/issues/343)) ([3e3299a](https://github.com/homarr-labs/homarr/commit/3e3299a358b44f86c850b3b96edf14e503d92151)) +* **deps:** update mantine monorepo to ^7.8.1 ([#377](https://github.com/homarr-labs/homarr/issues/377)) ([92b417a](https://github.com/homarr-labs/homarr/commit/92b417a37e070352d4830ab6d907421a89440308)) +* **deps:** update mantine monorepo to ^7.9.0 ([#423](https://github.com/homarr-labs/homarr/issues/423)) ([90b9d56](https://github.com/homarr-labs/homarr/commit/90b9d5672959e68c551b2bd9190b8ad97fbec1d0)) +* **deps:** update mantine monorepo to ^7.9.1 ([#457](https://github.com/homarr-labs/homarr/issues/457)) ([48d7aaa](https://github.com/homarr-labs/homarr/commit/48d7aaaf1d0e59bd2573bbe01a3421d14cd64be1)) +* **deps:** update mantine monorepo to ^7.9.2 ([#510](https://github.com/homarr-labs/homarr/issues/510)) ([abffc86](https://github.com/homarr-labs/homarr/commit/abffc866c084c387a553395519c172becaec0618)) +* **deps:** update nest monorepo to ^10.3.5 ([#245](https://github.com/homarr-labs/homarr/issues/245)) ([0ffb3f1](https://github.com/homarr-labs/homarr/commit/0ffb3f18b9bd8c90f826bcb29c257d656dbb91f5)) +* **deps:** update nextjs monorepo to ^14.1.0 ([#38](https://github.com/homarr-labs/homarr/issues/38)) ([dadfc0c](https://github.com/homarr-labs/homarr/commit/dadfc0c5d73395d2c49afbc7c67d0755e102b719)) +* **deps:** update nextjs monorepo to ^14.1.1 ([#147](https://github.com/homarr-labs/homarr/issues/147)) ([b407f2a](https://github.com/homarr-labs/homarr/commit/b407f2a9ac02b3ea6bfa22388e8e1150d2c82d48)) +* **deps:** update nextjs monorepo to ^14.1.2 ([#193](https://github.com/homarr-labs/homarr/issues/193)) ([8df514d](https://github.com/homarr-labs/homarr/commit/8df514dec883a90b3fcee8ef69efed87608618df)) +* **deps:** update nextjs monorepo to ^14.1.3 ([#208](https://github.com/homarr-labs/homarr/issues/208)) ([56d5e70](https://github.com/homarr-labs/homarr/commit/56d5e709bccdff4d37c6964dd1420721fc6f0356)) +* **deps:** update nextjs monorepo to ^14.1.4 ([#252](https://github.com/homarr-labs/homarr/issues/252)) ([28f630f](https://github.com/homarr-labs/homarr/commit/28f630f58b60260cd48990f9edf04173db5bd01d)) +* **deps:** update nextjs monorepo to ^14.2.10 ([#1109](https://github.com/homarr-labs/homarr/issues/1109)) ([fb55f12](https://github.com/homarr-labs/homarr/commit/fb55f1272d890307452cf7c7f3a54eb454da736f)) +* **deps:** update nextjs monorepo to ^14.2.11 ([#1117](https://github.com/homarr-labs/homarr/issues/1117)) ([7a56006](https://github.com/homarr-labs/homarr/commit/7a56006533d0fce5b288e1efe658e026abd062e1)) +* **deps:** update nextjs monorepo to ^14.2.12 ([#1146](https://github.com/homarr-labs/homarr/issues/1146)) ([8f5d7f8](https://github.com/homarr-labs/homarr/commit/8f5d7f83879e68b73f20303fbd9d3f4f70f69e3d)) +* **deps:** update nextjs monorepo to ^14.2.13 ([#1154](https://github.com/homarr-labs/homarr/issues/1154)) ([2258dc3](https://github.com/homarr-labs/homarr/commit/2258dc3ec66fd6d2c0ca9d7d2a689174a806586d)) +* **deps:** update nextjs monorepo to ^14.2.14 ([#1215](https://github.com/homarr-labs/homarr/issues/1215)) ([6f5c993](https://github.com/homarr-labs/homarr/commit/6f5c9935108511783b16c1a8206088e4845f9529)) +* **deps:** update nextjs monorepo to ^14.2.15 ([#1270](https://github.com/homarr-labs/homarr/issues/1270)) ([2bbe594](https://github.com/homarr-labs/homarr/commit/2bbe594cd28decee8934fc7338cdda9b77a2040c)) +* **deps:** update nextjs monorepo to ^14.2.16 ([#1355](https://github.com/homarr-labs/homarr/issues/1355)) ([aea65ea](https://github.com/homarr-labs/homarr/commit/aea65eadcd180e892d823ddccc2657b3beeb8acb)) +* **deps:** update nextjs monorepo to ^14.2.17 ([#1435](https://github.com/homarr-labs/homarr/issues/1435)) ([cd18458](https://github.com/homarr-labs/homarr/commit/cd18458d0c8a91c9068f8fbbfa49b5c0191e8f63)) +* **deps:** update nextjs monorepo to ^14.2.18 ([#1479](https://github.com/homarr-labs/homarr/issues/1479)) ([ccee3dd](https://github.com/homarr-labs/homarr/commit/ccee3dd21732be7106bf04af802c528351d132be)) +* **deps:** update nextjs monorepo to ^14.2.19 ([#1594](https://github.com/homarr-labs/homarr/issues/1594)) ([b0d6230](https://github.com/homarr-labs/homarr/commit/b0d623047ed0aae68741a50345610d2bc65cf86b)) +* **deps:** update nextjs monorepo to ^14.2.2 ([#345](https://github.com/homarr-labs/homarr/issues/345)) ([b465b95](https://github.com/homarr-labs/homarr/commit/b465b95ca26c1b0bc9035c7d2bd72d8a657870b3)) +* **deps:** update nextjs monorepo to ^14.2.20 ([#1610](https://github.com/homarr-labs/homarr/issues/1610)) ([ef65270](https://github.com/homarr-labs/homarr/commit/ef652707788ab68eeadd43dff908387340784f04)) +* **deps:** update nextjs monorepo to ^14.2.3 ([#381](https://github.com/homarr-labs/homarr/issues/381)) ([75e4e81](https://github.com/homarr-labs/homarr/commit/75e4e8176e36a995ebcd25387cae6435a5723b49)) +* **deps:** update nextjs monorepo to ^14.2.4 ([#658](https://github.com/homarr-labs/homarr/issues/658)) ([476fa59](https://github.com/homarr-labs/homarr/commit/476fa59079a3026fb1ce3d3c1b87a4b99425dccf)) +* **deps:** update nextjs monorepo to ^14.2.5 ([#779](https://github.com/homarr-labs/homarr/issues/779)) ([99175fe](https://github.com/homarr-labs/homarr/commit/99175feda492ff0b0d2d9d07c75d2bd45f69fbb5)) +* **deps:** update nextjs monorepo to ^14.2.6 ([#1009](https://github.com/homarr-labs/homarr/issues/1009)) ([1311e72](https://github.com/homarr-labs/homarr/commit/1311e72ca0a9c16db207d088809debd020da1318)) +* **deps:** update nextjs monorepo to ^14.2.7 ([#1041](https://github.com/homarr-labs/homarr/issues/1041)) ([3771a61](https://github.com/homarr-labs/homarr/commit/3771a61c49ca92f8567bb0905a696236a1e473a0)) +* **deps:** update nextjs monorepo to ^14.2.8 ([#1067](https://github.com/homarr-labs/homarr/issues/1067)) ([ca83872](https://github.com/homarr-labs/homarr/commit/ca83872151a867a42b3504a3eafff585a386b02d)) +* **deps:** update nextjs monorepo to ^14.2.9 ([#1091](https://github.com/homarr-labs/homarr/issues/1091)) ([3f076fa](https://github.com/homarr-labs/homarr/commit/3f076fafcd505b0b18781fc485dec8b144c8051f)) +* **deps:** update react monorepo to v19 (major) ([#1615](https://github.com/homarr-labs/homarr/issues/1615)) ([6f874e8](https://github.com/homarr-labs/homarr/commit/6f874e87abbc20a6e95cfbeb7bb7188d13599672)) +* **deps:** update tanstack-query monorepo ([#126](https://github.com/homarr-labs/homarr/issues/126)) ([71521c0](https://github.com/homarr-labs/homarr/commit/71521c076809fa3041ebf0ce4c9b9365adcf167b)) +* **deps:** update tanstack-query monorepo ([#141](https://github.com/homarr-labs/homarr/issues/141)) ([5d68300](https://github.com/homarr-labs/homarr/commit/5d68300600f0bd890aa4413ada41559f10afcf51)) +* **deps:** update tanstack-query monorepo ([#216](https://github.com/homarr-labs/homarr/issues/216)) ([efbc4cf](https://github.com/homarr-labs/homarr/commit/efbc4cf8fe62c4dd39fa2191238e1d62e5e98f9c)) +* **deps:** update tanstack-query monorepo ([#280](https://github.com/homarr-labs/homarr/issues/280)) ([e74926d](https://github.com/homarr-labs/homarr/commit/e74926d3825a7a31008faf6ec4ef00b6ab5ce669)) +* **deps:** update tanstack-query monorepo to ^5.18.1 ([#39](https://github.com/homarr-labs/homarr/issues/39)) ([717e919](https://github.com/homarr-labs/homarr/commit/717e9194500ad875e2c57bc088a3fa7ec08faf68)) +* **deps:** update tanstack-query monorepo to ^5.20.1 ([#75](https://github.com/homarr-labs/homarr/issues/75)) ([00f4a28](https://github.com/homarr-labs/homarr/commit/00f4a288a413383b4c412a1165eeba8a4c973a67)) +* **deps:** update tanstack-query monorepo to ^5.20.5 ([#86](https://github.com/homarr-labs/homarr/issues/86)) ([b77e652](https://github.com/homarr-labs/homarr/commit/b77e6528225a54839c5b09ad2464c6ab266259c6)) +* **deps:** update tanstack-query monorepo to ^5.21.4 ([#128](https://github.com/homarr-labs/homarr/issues/128)) ([a9a3d98](https://github.com/homarr-labs/homarr/commit/a9a3d98248a9ba518d941f8e437784a98984895d)) +* **deps:** update tanstack-query monorepo to ^5.21.7 ([#133](https://github.com/homarr-labs/homarr/issues/133)) ([e150577](https://github.com/homarr-labs/homarr/commit/e150577c7eea55b3f837951eeaa8fef41468c6af)) +* **deps:** update tanstack-query monorepo to ^5.24.1 ([#156](https://github.com/homarr-labs/homarr/issues/156)) ([3022e7f](https://github.com/homarr-labs/homarr/commit/3022e7f0af1d319e87398e09df27bd5824f0f8b4)) +* **deps:** update tanstack-query monorepo to ^5.24.6 ([#168](https://github.com/homarr-labs/homarr/issues/168)) ([7f2ab7f](https://github.com/homarr-labs/homarr/commit/7f2ab7f192b55f970c6902cde71f85c06a5f67df)) +* **deps:** update tanstack-query monorepo to ^5.24.8 ([#187](https://github.com/homarr-labs/homarr/issues/187)) ([f98046d](https://github.com/homarr-labs/homarr/commit/f98046d9e207bd068fa1cea19c4be0cba61c14c0)) +* **deps:** update tanstack-query monorepo to ^5.25.0 ([#196](https://github.com/homarr-labs/homarr/issues/196)) ([8c9adb3](https://github.com/homarr-labs/homarr/commit/8c9adb31f34991117c18ded417bf13312a04244a)) +* **deps:** update tanstack-query monorepo to ^5.28.0 ([#225](https://github.com/homarr-labs/homarr/issues/225)) ([9a203e8](https://github.com/homarr-labs/homarr/commit/9a203e8fac4379a703ad0d13380bb1a827791cd2)) +* **deps:** update tanstack-query monorepo to ^5.28.14 ([#299](https://github.com/homarr-labs/homarr/issues/299)) ([a4f316f](https://github.com/homarr-labs/homarr/commit/a4f316f10fc11579527722263249523591762e8b)) +* **deps:** update tanstack-query monorepo to ^5.28.4 ([#235](https://github.com/homarr-labs/homarr/issues/235)) ([30278f3](https://github.com/homarr-labs/homarr/commit/30278f37d248f0222dcd86e67a3310961c804a25)) +* **deps:** update tanstack-query monorepo to ^5.28.6 ([#256](https://github.com/homarr-labs/homarr/issues/256)) ([e4e3463](https://github.com/homarr-labs/homarr/commit/e4e3463d0464c37c32da83000ae971006157d1b2)) +* **deps:** update tanstack-query monorepo to ^5.28.8 ([#265](https://github.com/homarr-labs/homarr/issues/265)) ([4783aae](https://github.com/homarr-labs/homarr/commit/4783aaea20c44d823cb01857ffd050f7539948af)) +* **deps:** update tanstack-query monorepo to ^5.29.0 ([#313](https://github.com/homarr-labs/homarr/issues/313)) ([fffefbb](https://github.com/homarr-labs/homarr/commit/fffefbb4c8767ae5803429363ecf323d2384a6a0)) +* **deps:** update tanstack-query monorepo to ^5.29.2 ([#340](https://github.com/homarr-labs/homarr/issues/340)) ([859fdf4](https://github.com/homarr-labs/homarr/commit/859fdf4c440af5176401bdee236b5e19973182ef)) +* **deps:** update tanstack-query monorepo to ^5.32.0 ([#374](https://github.com/homarr-labs/homarr/issues/374)) ([0cdf0b7](https://github.com/homarr-labs/homarr/commit/0cdf0b73bfc410c7457fe7b379a380fdf83a938b)) +* **deps:** update tanstack-query monorepo to ^5.32.1 ([#402](https://github.com/homarr-labs/homarr/issues/402)) ([c988f3d](https://github.com/homarr-labs/homarr/commit/c988f3d7f827dd3121582a69fe1219dedb1ae246)) +* **deps:** update tanstack-query monorepo to ^5.34.1 ([#427](https://github.com/homarr-labs/homarr/issues/427)) ([fb43fc6](https://github.com/homarr-labs/homarr/commit/fb43fc604657e0ee3361db5fb3df8bdf68a22a51)) +* **deps:** update tanstack-query monorepo to ^5.34.2 ([#439](https://github.com/homarr-labs/homarr/issues/439)) ([08d1b6c](https://github.com/homarr-labs/homarr/commit/08d1b6c638c008936d67e1fe720313deaae147cd)) +* **deps:** update tanstack-query monorepo to ^5.35.1 ([#446](https://github.com/homarr-labs/homarr/issues/446)) ([96158bc](https://github.com/homarr-labs/homarr/commit/96158bcb5e0818f698f04f107dab24b6285f32df)) +* **deps:** update tanstack-query monorepo to ^5.35.5 ([#465](https://github.com/homarr-labs/homarr/issues/465)) ([8e6d143](https://github.com/homarr-labs/homarr/commit/8e6d143edc6613766ea86d3c84ef392aea867a0a)) +* **deps:** update tanstack-query monorepo to ^5.36.0 ([#481](https://github.com/homarr-labs/homarr/issues/481)) ([1570faa](https://github.com/homarr-labs/homarr/commit/1570faa20af2c1b4173ade77565691176219c601)) +* **deps:** update tanstack-query monorepo to ^5.36.2 ([#496](https://github.com/homarr-labs/homarr/issues/496)) ([023feaf](https://github.com/homarr-labs/homarr/commit/023feafafe5f78b73870a48a06d037b563999d5d)) +* **deps:** update tanstack-query monorepo to ^5.37.1 ([#513](https://github.com/homarr-labs/homarr/issues/513)) ([b312032](https://github.com/homarr-labs/homarr/commit/b312032f02db6fac0e95456ef23cf84d4ab485b0)) +* **deps:** update tanstack-query monorepo to ^5.40.0 ([#552](https://github.com/homarr-labs/homarr/issues/552)) ([8f50def](https://github.com/homarr-labs/homarr/commit/8f50def4c931545fbe4b24a2c501c725e088ce9f)) +* **deps:** update tanstack-query monorepo to ^5.40.1 ([#617](https://github.com/homarr-labs/homarr/issues/617)) ([946ea87](https://github.com/homarr-labs/homarr/commit/946ea8753fd45582ba15b6fc69a434039d341b1d)) +* **deps:** update tanstack-query monorepo to ^5.44.0 ([#657](https://github.com/homarr-labs/homarr/issues/657)) ([8b3bc03](https://github.com/homarr-labs/homarr/commit/8b3bc03b9be9d70d11d982869250d575b24ca4b8)) +* **deps:** update tanstack-query monorepo to ^5.45.0 ([#660](https://github.com/homarr-labs/homarr/issues/660)) ([5547e52](https://github.com/homarr-labs/homarr/commit/5547e520016b92c0981899099cce1bf82f7d1a00)) +* **deps:** update tanstack-query monorepo to ^5.45.1 ([#677](https://github.com/homarr-labs/homarr/issues/677)) ([33e8cc7](https://github.com/homarr-labs/homarr/commit/33e8cc7412e2cc4541ae5e58ae45b20ffa74972a)) +* **deps:** update tanstack-query monorepo to ^5.47.0 ([#713](https://github.com/homarr-labs/homarr/issues/713)) ([75748df](https://github.com/homarr-labs/homarr/commit/75748dfbc35057b7f44e836fd2864c76c2705237)) +* **deps:** update tanstack-query monorepo to ^5.48.0 ([#714](https://github.com/homarr-labs/homarr/issues/714)) ([a76e941](https://github.com/homarr-labs/homarr/commit/a76e941378a2d8669a9b4484b8301f5557dda1a3)) +* **deps:** update tanstack-query monorepo to ^5.49.0 ([#728](https://github.com/homarr-labs/homarr/issues/728)) ([531cd0d](https://github.com/homarr-labs/homarr/commit/531cd0de2520429d3b3270e05fc5d8e9c5732163)) +* **deps:** update tanstack-query monorepo to ^5.49.2 ([#730](https://github.com/homarr-labs/homarr/issues/730)) ([8ee0d67](https://github.com/homarr-labs/homarr/commit/8ee0d67a36b30ae1e5f679a0c24014c3c79709ca)) +* **deps:** update tanstack-query monorepo to ^5.50.1 ([#747](https://github.com/homarr-labs/homarr/issues/747)) ([a67050e](https://github.com/homarr-labs/homarr/commit/a67050e77b14a0ad1e6b960dad24f4a35779f858)) +* **deps:** update tanstack-query monorepo to ^5.51.1 ([#782](https://github.com/homarr-labs/homarr/issues/782)) ([be4748b](https://github.com/homarr-labs/homarr/commit/be4748b8fa5cf2b7f17acd03753115b9562f3285)) +* **deps:** update tanstack-query monorepo to ^5.51.11 ([#836](https://github.com/homarr-labs/homarr/issues/836)) ([14d19fc](https://github.com/homarr-labs/homarr/commit/14d19fcd8bf9577cd483b6bb89e1cc3bbaf484b1)) +* **deps:** update tanstack-query monorepo to ^5.51.14 ([#866](https://github.com/homarr-labs/homarr/issues/866)) ([04a836e](https://github.com/homarr-labs/homarr/commit/04a836e824e607f48b876d6882aecb5de3b666ae)) +* **deps:** update tanstack-query monorepo to ^5.51.15 ([#868](https://github.com/homarr-labs/homarr/issues/868)) ([63b3c1b](https://github.com/homarr-labs/homarr/commit/63b3c1bff19d9265ef2c80dfbbc9058354a9acfb)) +* **deps:** update tanstack-query monorepo to ^5.51.16 ([#892](https://github.com/homarr-labs/homarr/issues/892)) ([3a5f818](https://github.com/homarr-labs/homarr/commit/3a5f818e7cbef6365f9ae89996657cdb418d7917)) +* **deps:** update tanstack-query monorepo to ^5.51.17 ([#899](https://github.com/homarr-labs/homarr/issues/899)) ([5c73b54](https://github.com/homarr-labs/homarr/commit/5c73b544285d1fca753168a796e1143da5ffc37d)) +* **deps:** update tanstack-query monorepo to ^5.51.18 ([#900](https://github.com/homarr-labs/homarr/issues/900)) ([26615d8](https://github.com/homarr-labs/homarr/commit/26615d80e795c050e2ac94ba133cbf23c74b2d27)) +* **deps:** update tanstack-query monorepo to ^5.51.21 ([#905](https://github.com/homarr-labs/homarr/issues/905)) ([2a459dd](https://github.com/homarr-labs/homarr/commit/2a459dda205448ebfa3d8451a5229a82fa850fbb)) +* **deps:** update tanstack-query monorepo to ^5.51.23 ([#936](https://github.com/homarr-labs/homarr/issues/936)) ([f9e2df0](https://github.com/homarr-labs/homarr/commit/f9e2df085b2ba737c2ef6375474865b34a3f43cf)) +* **deps:** update tanstack-query monorepo to ^5.51.24 ([#997](https://github.com/homarr-labs/homarr/issues/997)) ([2f77be8](https://github.com/homarr-labs/homarr/commit/2f77be8045ea67d1f5db20bd140c9e19af903571)) +* **deps:** update tanstack-query monorepo to ^5.51.3 ([#821](https://github.com/homarr-labs/homarr/issues/821)) ([05bbc19](https://github.com/homarr-labs/homarr/commit/05bbc19a15b8f8d7cdef4b9fee3174b28918bc9d)) +* **deps:** update tanstack-query monorepo to ^5.51.4 ([#824](https://github.com/homarr-labs/homarr/issues/824)) ([86c729a](https://github.com/homarr-labs/homarr/commit/86c729a83f01cb4a3ce5413b6b4117505b6b61f4)) +* **deps:** update tanstack-query monorepo to ^5.51.5 ([#829](https://github.com/homarr-labs/homarr/issues/829)) ([a4edda6](https://github.com/homarr-labs/homarr/commit/a4edda6932ed5008fe4609b55636232a7ca500ce)) +* **deps:** update tanstack-query monorepo to ^5.51.8 ([#830](https://github.com/homarr-labs/homarr/issues/830)) ([ee2703c](https://github.com/homarr-labs/homarr/commit/ee2703ca4be312e5e0f2b9964fa3fb1d0bd074c1)) +* **deps:** update tanstack-query monorepo to ^5.51.9 ([#831](https://github.com/homarr-labs/homarr/issues/831)) ([c8f3eb6](https://github.com/homarr-labs/homarr/commit/c8f3eb69e54a732274fd85841b1d1181fbc9a279)) +* **deps:** update tanstack-query monorepo to ^5.52.0 ([#1002](https://github.com/homarr-labs/homarr/issues/1002)) ([432af79](https://github.com/homarr-labs/homarr/commit/432af7905510283779aacf7331a82a3d53f0c899)) +* **deps:** update tanstack-query monorepo to ^5.52.1 ([#1013](https://github.com/homarr-labs/homarr/issues/1013)) ([8779b7d](https://github.com/homarr-labs/homarr/commit/8779b7d6073f41b52bf2fadda25ccab8d1ae1622)) +* **deps:** update tanstack-query monorepo to ^5.52.2 ([#1037](https://github.com/homarr-labs/homarr/issues/1037)) ([48d01e3](https://github.com/homarr-labs/homarr/commit/48d01e3c6ceb9fd4e60f0bd720374da53206d94e)) +* **deps:** update tanstack-query monorepo to ^5.52.3 ([#1043](https://github.com/homarr-labs/homarr/issues/1043)) ([afb6adf](https://github.com/homarr-labs/homarr/commit/afb6adf1e68f0f1b6b819a32a95d0a28855e88c4)) +* **deps:** update tanstack-query monorepo to ^5.53.1 ([#1045](https://github.com/homarr-labs/homarr/issues/1045)) ([775c359](https://github.com/homarr-labs/homarr/commit/775c3597dcd9008606446d066ddb46dc758b5689)) +* **deps:** update tanstack-query monorepo to ^5.53.2 ([#1055](https://github.com/homarr-labs/homarr/issues/1055)) ([d69fed6](https://github.com/homarr-labs/homarr/commit/d69fed6514bef0ee5cc235cca86888d040fae562)) +* **deps:** update tanstack-query monorepo to ^5.53.3 ([#1056](https://github.com/homarr-labs/homarr/issues/1056)) ([8fe162e](https://github.com/homarr-labs/homarr/commit/8fe162e16c4c06ca453437d0ee4e6491ecb2ed84)) +* **deps:** update tanstack-query monorepo to ^5.54.1 ([#1063](https://github.com/homarr-labs/homarr/issues/1063)) ([9e1faa0](https://github.com/homarr-labs/homarr/commit/9e1faa03b120a225114f7e8bf4cc683be243c4f6)) +* **deps:** update tanstack-query monorepo to ^5.55.0 ([#1070](https://github.com/homarr-labs/homarr/issues/1070)) ([00d5020](https://github.com/homarr-labs/homarr/commit/00d5020824f6661575d7201e2524151defc35585)) +* **deps:** update tanstack-query monorepo to ^5.55.2 ([#1084](https://github.com/homarr-labs/homarr/issues/1084)) ([930bc2d](https://github.com/homarr-labs/homarr/commit/930bc2d7d205e7883898fb15deefc3f5abfedced)) +* **deps:** update tanstack-query monorepo to ^5.55.4 ([#1086](https://github.com/homarr-labs/homarr/issues/1086)) ([36a7a18](https://github.com/homarr-labs/homarr/commit/36a7a18c35258f9e592755ef10583b603a5bb39e)) +* **deps:** update tanstack-query monorepo to ^5.56.0 ([#1112](https://github.com/homarr-labs/homarr/issues/1112)) ([703ecec](https://github.com/homarr-labs/homarr/commit/703ecece634a284070b15edbd4580ffbd3a58502)) +* **deps:** update tanstack-query monorepo to ^5.56.1 ([#1114](https://github.com/homarr-labs/homarr/issues/1114)) ([2d4681d](https://github.com/homarr-labs/homarr/commit/2d4681d07989bf8388152893a7e194ead1e4c59d)) +* **deps:** update tanstack-query monorepo to ^5.56.2 ([#1116](https://github.com/homarr-labs/homarr/issues/1116)) ([cae9a80](https://github.com/homarr-labs/homarr/commit/cae9a800c47e23b5ef674c19ba5a1eea127018a3)) +* **deps:** update tanstack-query monorepo to ^5.59.0 ([#1214](https://github.com/homarr-labs/homarr/issues/1214)) ([c3d54b4](https://github.com/homarr-labs/homarr/commit/c3d54b49a0ba0ae2c2a4cc3d1651cb01df2efdf7)) +* **deps:** update tanstack-query monorepo to ^5.59.14 ([#1282](https://github.com/homarr-labs/homarr/issues/1282)) ([df8f6d2](https://github.com/homarr-labs/homarr/commit/df8f6d25d4accd486274df15eb620b28fb545826)) +* **deps:** update tanstack-query monorepo to ^5.59.15 ([#1298](https://github.com/homarr-labs/homarr/issues/1298)) ([bb0026a](https://github.com/homarr-labs/homarr/commit/bb0026a9fd6093cf54dc5fdcf027ea1033ac8454)) +* **deps:** update tanstack-query monorepo to ^5.59.16 ([#1361](https://github.com/homarr-labs/homarr/issues/1361)) ([b542bad](https://github.com/homarr-labs/homarr/commit/b542bad939527d1de5a0eb0a8c384cf4f6267436)) +* **deps:** update tanstack-query monorepo to ^5.59.17 ([#1403](https://github.com/homarr-labs/homarr/issues/1403)) ([deb5a71](https://github.com/homarr-labs/homarr/commit/deb5a716db1312fcbafbd244d3399a35ab50c4e9)) +* **deps:** update tanstack-query monorepo to ^5.59.19 ([#1410](https://github.com/homarr-labs/homarr/issues/1410)) ([8983734](https://github.com/homarr-labs/homarr/commit/8983734408e9c5ea89bc3fb0e011e9030824a43c)) +* **deps:** update tanstack-query monorepo to ^5.59.20 ([#1438](https://github.com/homarr-labs/homarr/issues/1438)) ([e05567d](https://github.com/homarr-labs/homarr/commit/e05567d100e3ff99a1d41099ffe5b9333b0eb7a7)) +* **deps:** update tanstack-query monorepo to ^5.59.3 ([#1274](https://github.com/homarr-labs/homarr/issues/1274)) ([e3cd8a8](https://github.com/homarr-labs/homarr/commit/e3cd8a8b25c736e93dec8d4df4be368007785f61)) +* **deps:** update tanstack-query monorepo to ^5.59.6 ([#1276](https://github.com/homarr-labs/homarr/issues/1276)) ([efd06ea](https://github.com/homarr-labs/homarr/commit/efd06ea1079aca15b75f358916e20b13e39ac568)) +* **deps:** update tanstack-query monorepo to ^5.59.9 ([#1278](https://github.com/homarr-labs/homarr/issues/1278)) ([0ca140f](https://github.com/homarr-labs/homarr/commit/0ca140f4ff8f74a5eef496864d2bcd95e389f329)) +* **deps:** update tanstack-query monorepo to ^5.60.2 ([#1482](https://github.com/homarr-labs/homarr/issues/1482)) ([12c3bb9](https://github.com/homarr-labs/homarr/commit/12c3bb98485f3b38ba12d3fc84b7498b78fd1d8f)) +* **deps:** update tanstack-query monorepo to ^5.60.4 ([#1488](https://github.com/homarr-labs/homarr/issues/1488)) ([41f816b](https://github.com/homarr-labs/homarr/commit/41f816be5b9561398361153d3f9a07cd2e3cc6e1)) +* **deps:** update tanstack-query monorepo to ^5.60.5 ([#1489](https://github.com/homarr-labs/homarr/issues/1489)) ([6dcf1ad](https://github.com/homarr-labs/homarr/commit/6dcf1ad3446f0c564ec7c21c0fc8154e5cd1ce68)) +* **deps:** update tanstack-query monorepo to ^5.60.6 ([#1500](https://github.com/homarr-labs/homarr/issues/1500)) ([2f76e53](https://github.com/homarr-labs/homarr/commit/2f76e537b7a8a30b1a7801753b44cfd7a25dc2d6)) +* **deps:** update tanstack-query monorepo to ^5.61.0 ([#1510](https://github.com/homarr-labs/homarr/issues/1510)) ([ed10d63](https://github.com/homarr-labs/homarr/commit/ed10d63a04a2b5a8dad0ffb51fca35d8c0e88a34)) +* **deps:** update tanstack-query monorepo to ^5.61.3 ([#1536](https://github.com/homarr-labs/homarr/issues/1536)) ([24daba7](https://github.com/homarr-labs/homarr/commit/24daba743ed645e6a974bb212e28b745acdd34f7)) +* **deps:** update tanstack-query monorepo to ^5.61.4 ([#1555](https://github.com/homarr-labs/homarr/issues/1555)) ([91a199f](https://github.com/homarr-labs/homarr/commit/91a199f7d6014c97425b55f2a419b252b766b4c3)) +* **deps:** update tanstack-query monorepo to ^5.61.5 ([#1559](https://github.com/homarr-labs/homarr/issues/1559)) ([f2e7349](https://github.com/homarr-labs/homarr/commit/f2e7349cbdfc065b52951d3a54a22344dca6807b)) +* **deps:** update tanstack-query monorepo to ^5.62.0 ([#1569](https://github.com/homarr-labs/homarr/issues/1569)) ([6ad5fd5](https://github.com/homarr-labs/homarr/commit/6ad5fd55295622429035aa7f59e478ada19ec36a)) +* **deps:** update tanstack-query monorepo to ^5.62.1 ([#1584](https://github.com/homarr-labs/homarr/issues/1584)) ([0e01dd8](https://github.com/homarr-labs/homarr/commit/0e01dd86950beac24259ac1269f0159c7c33e35c)) +* **deps:** update tanstack-query monorepo to ^5.62.2 ([#1590](https://github.com/homarr-labs/homarr/issues/1590)) ([3b705f4](https://github.com/homarr-labs/homarr/commit/3b705f43b89b4c844522925c1d03a2822a2986a9)) +* **deps:** update tanstack-query monorepo to ^5.62.3 ([#1621](https://github.com/homarr-labs/homarr/issues/1621)) ([42ab783](https://github.com/homarr-labs/homarr/commit/42ab783085ab0a1998d62975aac796af1fc80a3c)) +* **deps:** update tanstack-query monorepo to ^5.62.7 ([#1638](https://github.com/homarr-labs/homarr/issues/1638)) ([e692cc8](https://github.com/homarr-labs/homarr/commit/e692cc891713802cdf8655eb54223ef8e30377ba)) +* **deps:** update tanstack-query monorepo to ^5.62.8 ([#1682](https://github.com/homarr-labs/homarr/issues/1682)) ([28667c5](https://github.com/homarr-labs/homarr/commit/28667c5e1aa5b9c9c640f251fcb4e9e1063fa922)) +* **deps:** update tanstack-query monorepo to v5.38.0 ([#551](https://github.com/homarr-labs/homarr/issues/551)) ([a029abe](https://github.com/homarr-labs/homarr/commit/a029abe6f3fa762e879717bd66bc4e8bbde3558b)) +* **deps:** update testcontainers-node monorepo to ^10.13.2 ([#1233](https://github.com/homarr-labs/homarr/issues/1233)) ([8ea8b2d](https://github.com/homarr-labs/homarr/commit/8ea8b2ded55e3d026d3d13b1baa09f740b2d3a54)) +* **deps:** update testcontainers-node monorepo to ^10.14.0 ([#1434](https://github.com/homarr-labs/homarr/issues/1434)) ([31c661b](https://github.com/homarr-labs/homarr/commit/31c661bc69c32403dd7eff262b62d86debef05bc)) +* **deps:** update testcontainers-node monorepo to ^10.15.0 ([#1521](https://github.com/homarr-labs/homarr/issues/1521)) ([6018b20](https://github.com/homarr-labs/homarr/commit/6018b20d4e2be0991c735ca690bd91062285b2bb)) +* **deps:** update testcontainers-node monorepo to ^10.16.0 ([#1604](https://github.com/homarr-labs/homarr/issues/1604)) ([feb93ef](https://github.com/homarr-labs/homarr/commit/feb93ef0c71089a005c31b4f0798a0b20dc0e36b)) +* **deps:** update tiptap monorepo to ^2.2.1 ([#40](https://github.com/homarr-labs/homarr/issues/40)) ([1e01312](https://github.com/homarr-labs/homarr/commit/1e01312fcd5e7e267db330dfdb72a8d8b83fadfd)) +* **deps:** update tiptap monorepo to ^2.2.2 ([#63](https://github.com/homarr-labs/homarr/issues/63)) ([593bc9c](https://github.com/homarr-labs/homarr/commit/593bc9ca1c05bfd69b35d6bb2b7c34d3dabe7303)) +* **deps:** update tiptap monorepo to ^2.2.3 ([#95](https://github.com/homarr-labs/homarr/issues/95)) ([3e44644](https://github.com/homarr-labs/homarr/commit/3e44644ef6e8f8e8b7d898f5794405d2e61eb3af)) +* **deps:** update tiptap monorepo to ^2.2.4 ([#153](https://github.com/homarr-labs/homarr/issues/153)) ([212063a](https://github.com/homarr-labs/homarr/commit/212063a51eb8f9a48fcfe39df9a79dca31116c08)) +* **deps:** update tiptap monorepo to ^2.2.5 ([#315](https://github.com/homarr-labs/homarr/issues/315)) ([75224e0](https://github.com/homarr-labs/homarr/commit/75224e05334361356d841c5878600709324fa3e8)) +* **deps:** update tiptap monorepo to v2.10.0 ([#1507](https://github.com/homarr-labs/homarr/issues/1507)) ([860d2e4](https://github.com/homarr-labs/homarr/commit/860d2e4f69bbdf9b3ffb37b26d514e86ceca378a)) +* **deps:** update tiptap monorepo to v2.10.1 ([#1516](https://github.com/homarr-labs/homarr/issues/1516)) ([85a69b1](https://github.com/homarr-labs/homarr/commit/85a69b13e38743d487e213012cf59b64ba52da67)) +* **deps:** update tiptap monorepo to v2.10.2 ([#1520](https://github.com/homarr-labs/homarr/issues/1520)) ([ba4c9a6](https://github.com/homarr-labs/homarr/commit/ba4c9a683ee533bd214faa8f834fb3fe8408b6bb)) +* **deps:** update tiptap monorepo to v2.10.3 ([#1556](https://github.com/homarr-labs/homarr/issues/1556)) ([c1fe655](https://github.com/homarr-labs/homarr/commit/c1fe6551ce46c00304f1a9c1e6d2d7f301f47dcb)) +* **deps:** update tiptap monorepo to v2.3.0 ([#317](https://github.com/homarr-labs/homarr/issues/317)) ([847adff](https://github.com/homarr-labs/homarr/commit/847adffe7b32310924d0e317fbc4379ed84bbca1)) +* **deps:** update tiptap monorepo to v2.3.1 ([#403](https://github.com/homarr-labs/homarr/issues/403)) ([876f21a](https://github.com/homarr-labs/homarr/commit/876f21a26dba4a2bf58a087d9d954c61baf30d07)) +* **deps:** update tiptap monorepo to v2.3.2 ([#459](https://github.com/homarr-labs/homarr/issues/459)) ([382be49](https://github.com/homarr-labs/homarr/commit/382be496ffb51bf16ff2b50689707503e610243c)) +* **deps:** update tiptap monorepo to v2.4.0 ([#494](https://github.com/homarr-labs/homarr/issues/494)) ([b18b364](https://github.com/homarr-labs/homarr/commit/b18b3642708dd36b6d269c78e8f0ce6efa6e1d17)) +* **deps:** update tiptap monorepo to v2.5.0 ([#811](https://github.com/homarr-labs/homarr/issues/811)) ([7f341ef](https://github.com/homarr-labs/homarr/commit/7f341efdb304cb9479bcce75b02f3d48ed99a8ad)) +* **deps:** update tiptap monorepo to v2.5.1 ([#813](https://github.com/homarr-labs/homarr/issues/813)) ([08ba282](https://github.com/homarr-labs/homarr/commit/08ba28252872455d960b63d688b13fffbca8edde)) +* **deps:** update tiptap monorepo to v2.5.2 ([#822](https://github.com/homarr-labs/homarr/issues/822)) ([b82128a](https://github.com/homarr-labs/homarr/commit/b82128a90cdef599b976625ab58bc20d30a78964)) +* **deps:** update tiptap monorepo to v2.5.3 ([#825](https://github.com/homarr-labs/homarr/issues/825)) ([015b42a](https://github.com/homarr-labs/homarr/commit/015b42aa61be681fc31359c00113f18331728a31)) +* **deps:** update tiptap monorepo to v2.5.4 ([#828](https://github.com/homarr-labs/homarr/issues/828)) ([baf552b](https://github.com/homarr-labs/homarr/commit/baf552bf52e35616c072e33d26014b0c181b6d46)) +* **deps:** update tiptap monorepo to v2.5.5 ([#853](https://github.com/homarr-labs/homarr/issues/853)) ([c512ddb](https://github.com/homarr-labs/homarr/commit/c512ddba493994f1b5a15dde58c32b704697fa1b)) +* **deps:** update tiptap monorepo to v2.5.6 ([#863](https://github.com/homarr-labs/homarr/issues/863)) ([d70e99c](https://github.com/homarr-labs/homarr/commit/d70e99c9734d8997a1f8a97fdf54aea1da08cc05)) +* **deps:** update tiptap monorepo to v2.5.7 ([#869](https://github.com/homarr-labs/homarr/issues/869)) ([89ab1df](https://github.com/homarr-labs/homarr/commit/89ab1df2dbdb19f4079f98289eeaeff591314fef)) +* **deps:** update tiptap monorepo to v2.5.8 ([#887](https://github.com/homarr-labs/homarr/issues/887)) ([e0566df](https://github.com/homarr-labs/homarr/commit/e0566dfcfa56c50b744a872ee0623f374696efee)) +* **deps:** update tiptap monorepo to v2.5.9 ([#922](https://github.com/homarr-labs/homarr/issues/922)) ([c6bb272](https://github.com/homarr-labs/homarr/commit/c6bb272318eccc4cf9c2790513a89cec650526e5)) +* **deps:** update tiptap monorepo to v2.6.1 ([#970](https://github.com/homarr-labs/homarr/issues/970)) ([4a34ec9](https://github.com/homarr-labs/homarr/commit/4a34ec91e5041acf257a1049a7b0c29e509b1585)) +* **deps:** update tiptap monorepo to v2.6.2 ([#972](https://github.com/homarr-labs/homarr/issues/972)) ([81a13b0](https://github.com/homarr-labs/homarr/commit/81a13b0e59eb776ca55782320f4967993e564819)) +* **deps:** update tiptap monorepo to v2.6.3 ([#980](https://github.com/homarr-labs/homarr/issues/980)) ([cc61e27](https://github.com/homarr-labs/homarr/commit/cc61e27fad4c058df6da8bdf49b2bf44d5fc0206)) +* **deps:** update tiptap monorepo to v2.6.4 ([#981](https://github.com/homarr-labs/homarr/issues/981)) ([0ba647a](https://github.com/homarr-labs/homarr/commit/0ba647ad511f45ad2fb1d35bc05f1876547602d0)) +* **deps:** update tiptap monorepo to v2.6.5 ([#1005](https://github.com/homarr-labs/homarr/issues/1005)) ([d401c8f](https://github.com/homarr-labs/homarr/commit/d401c8fa0ff47caef8e6f17aba39cf52310f6d7e)) +* **deps:** update tiptap monorepo to v2.6.6 ([#1015](https://github.com/homarr-labs/homarr/issues/1015)) ([cbf2ecf](https://github.com/homarr-labs/homarr/commit/cbf2ecfb9d3036e4077968c6ffb6c676b1e46308)) +* **deps:** update tiptap monorepo to v2.7.1 ([#1139](https://github.com/homarr-labs/homarr/issues/1139)) ([657c2ee](https://github.com/homarr-labs/homarr/commit/657c2eef80a6562c45c7d2a3b63fb03edff8eb3e)) +* **deps:** update tiptap monorepo to v2.7.2 ([#1150](https://github.com/homarr-labs/homarr/issues/1150)) ([d0e9e0f](https://github.com/homarr-labs/homarr/commit/d0e9e0f09da9afebf714c201b97528b743cc8915)) +* **deps:** update tiptap monorepo to v2.7.3 ([#1182](https://github.com/homarr-labs/homarr/issues/1182)) ([b2143ed](https://github.com/homarr-labs/homarr/commit/b2143eddeba787670d749a0f1e440936be7136d7)) +* **deps:** update tiptap monorepo to v2.7.4 ([#1186](https://github.com/homarr-labs/homarr/issues/1186)) ([4795c8c](https://github.com/homarr-labs/homarr/commit/4795c8c557f80e0019779f00afc58f053f9d6f40)) +* **deps:** update tiptap monorepo to v2.8.0 ([#1206](https://github.com/homarr-labs/homarr/issues/1206)) ([7dd4d4e](https://github.com/homarr-labs/homarr/commit/7dd4d4ec7be610c510caca1f8aa93e67095d05ed)) +* **deps:** update tiptap monorepo to v2.9.0 ([#1352](https://github.com/homarr-labs/homarr/issues/1352)) ([c3b9d98](https://github.com/homarr-labs/homarr/commit/c3b9d981f78b8131f269ec8b6b43f774196005ab)) +* **deps:** update tiptap monorepo to v2.9.1 ([#1360](https://github.com/homarr-labs/homarr/issues/1360)) ([d4919dc](https://github.com/homarr-labs/homarr/commit/d4919dc908748f61320e24f529a881547a124e7b)) +* **deps:** update typescript-eslint monorepo to ^6.20.0 ([#41](https://github.com/homarr-labs/homarr/issues/41)) ([4815230](https://github.com/homarr-labs/homarr/commit/4815230f8b0d3f9b88e72bbb4fb5f4e87daf81c1)) +* **deps:** update typescript-eslint monorepo to ^6.21.0 ([#58](https://github.com/homarr-labs/homarr/issues/58)) ([e683d61](https://github.com/homarr-labs/homarr/commit/e683d61568b61268dd04c50a31b18028b63a0a1b)) +* **deps:** update typescript-eslint monorepo to ^7.0.2 ([#122](https://github.com/homarr-labs/homarr/issues/122)) ([859eeed](https://github.com/homarr-labs/homarr/commit/859eeed32963f41b906d6dac5f16b9d9cd6ffd9e)) +* **deps:** update typescript-eslint monorepo to ^7.1.0 ([#159](https://github.com/homarr-labs/homarr/issues/159)) ([8e53792](https://github.com/homarr-labs/homarr/commit/8e5379225ad1df796a9f4829f4f8af7a41cae9d8)) +* **deps:** update typescript-eslint monorepo to ^7.1.1 ([#192](https://github.com/homarr-labs/homarr/issues/192)) ([27a63db](https://github.com/homarr-labs/homarr/commit/27a63dbf7a276d615c6de01b47e35830daff5cc9)) +* **deps:** update typescript-eslint monorepo to ^7.10.0 ([#562](https://github.com/homarr-labs/homarr/issues/562)) ([2bc0431](https://github.com/homarr-labs/homarr/commit/2bc0431e4e533476f8f7ecff2114b43759c33d9a)) +* **deps:** update typescript-eslint monorepo to ^7.11.0 ([#565](https://github.com/homarr-labs/homarr/issues/565)) ([c20f7a6](https://github.com/homarr-labs/homarr/commit/c20f7a64a0e47e2604645cc494b9d5cded15219a)) +* **deps:** update typescript-eslint monorepo to ^7.12.0 ([#616](https://github.com/homarr-labs/homarr/issues/616)) ([2623708](https://github.com/homarr-labs/homarr/commit/2623708c6dcf4ccd6c291a2548d68a918220dbed)) +* **deps:** update typescript-eslint monorepo to ^7.2.0 ([#218](https://github.com/homarr-labs/homarr/issues/218)) ([ea79953](https://github.com/homarr-labs/homarr/commit/ea79953353f0645849acbad2613f72d45f3894ea)) +* **deps:** update typescript-eslint monorepo to ^7.3.1 ([#247](https://github.com/homarr-labs/homarr/issues/247)) ([36e509a](https://github.com/homarr-labs/homarr/commit/36e509a474bc38a3b6c012bd566b73054f170f84)) +* **deps:** update typescript-eslint monorepo to ^7.5.0 ([#298](https://github.com/homarr-labs/homarr/issues/298)) ([54a7d1f](https://github.com/homarr-labs/homarr/commit/54a7d1f4ae2e470924d578bd507335e54d6c517a)) +* **deps:** update typescript-eslint monorepo to ^7.6.0 ([#329](https://github.com/homarr-labs/homarr/issues/329)) ([2ccb7d1](https://github.com/homarr-labs/homarr/commit/2ccb7d17655d3b9af67f30aa21a93764eeb81ac4)) +* **deps:** update typescript-eslint monorepo to ^7.7.1 ([#354](https://github.com/homarr-labs/homarr/issues/354)) ([0342a17](https://github.com/homarr-labs/homarr/commit/0342a177bb4a5cb642f79411a6003eca3a3a3e6d)) +* **deps:** update typescript-eslint monorepo to ^7.8.0 ([#395](https://github.com/homarr-labs/homarr/issues/395)) ([584483a](https://github.com/homarr-labs/homarr/commit/584483aa9cf309e3efa83f00ab735797638210ee)) +* **deps:** update typescript-eslint monorepo to ^7.9.0 ([#491](https://github.com/homarr-labs/homarr/issues/491)) ([a702f7d](https://github.com/homarr-labs/homarr/commit/a702f7dc67a3b63667ae019b4d807d54dc925ae0)) +* **deps:** update typescript-eslint monorepo to v7 ([#87](https://github.com/homarr-labs/homarr/issues/87)) ([f913384](https://github.com/homarr-labs/homarr/commit/f91338446df1eafce92842fa0ce9ebdabea7f629)) +* **deps:** update typescript-eslint monorepo to v7.10.0 ([#529](https://github.com/homarr-labs/homarr/issues/529)) ([30fe9fe](https://github.com/homarr-labs/homarr/commit/30fe9fef844e7cac5a59185926643baeb5e5ed2e)) +* **deps:** update xterm monorepo ([#312](https://github.com/homarr-labs/homarr/issues/312)) ([a5b8fdb](https://github.com/homarr-labs/homarr/commit/a5b8fdb3977c6613cfe592b20f57c0388e0c6229)) +* disable env validation in ci ([d7a30cd](https://github.com/homarr-labs/homarr/commit/d7a30cd0dd2dfd0e7db86d0c22780cf4c1e6423e)) +* disable env validation in ci ([c84fb63](https://github.com/homarr-labs/homarr/commit/c84fb63b25b199466cf1ba6f34ec5fd31d2a434c)) +* dispatch request-logger hides negative numbers, dates and date times ([#1506](https://github.com/homarr-labs/homarr/issues/1506)) ([2ffa9d0](https://github.com/homarr-labs/homarr/commit/2ffa9d0e712233b19ade71ec62fcf34de2128340)) +* display on safari ([#1071](https://github.com/homarr-labs/homarr/issues/1071)) ([753d091](https://github.com/homarr-labs/homarr/commit/753d091dbbc5665276461f5e1d79224ea1c0deb7)) +* DnsHole controls timer ([#953](https://github.com/homarr-labs/homarr/issues/953)) ([69e69ee](https://github.com/homarr-labs/homarr/commit/69e69ee315535555a8fd4cb43273357c9a4ce24b)) +* docker build ([#777](https://github.com/homarr-labs/homarr/issues/777)) ([01eb846](https://github.com/homarr-labs/homarr/commit/01eb84654d57afc2164ae8b7912752ecb6631f43)) +* docker build not working ([#1365](https://github.com/homarr-labs/homarr/issues/1365)) ([041006c](https://github.com/homarr-labs/homarr/commit/041006c181d7a1599400ce6d296d773c13f396b0)) +* docker development path in package.json ([#416](https://github.com/homarr-labs/homarr/issues/416)) ([48c2473](https://github.com/homarr-labs/homarr/commit/48c2473ab31354a492b86aa5d2d3319cbcadccea)) +* docker platforms ([f0d6676](https://github.com/homarr-labs/homarr/commit/f0d6676917c06a068aa432f49e5d74fc2ad45631)) +* docker push flag ([eab5c10](https://github.com/homarr-labs/homarr/commit/eab5c10fa6b36c22ee4bf1526d1000bc5137ac7b)) +* docker push flag ([1128110](https://github.com/homarr-labs/homarr/commit/1128110be386297ef0e128da477c1d9572336cad)) +* email verified check is in a newline in users table ([#1218](https://github.com/homarr-labs/homarr/issues/1218)) ([8b5ea3c](https://github.com/homarr-labs/homarr/commit/8b5ea3c5d3af5e904467591b9e066488b6a4abc1)) +* empty wrappers without items should not be visible in view mode ([#1026](https://github.com/homarr-labs/homarr/issues/1026)) ([022fad9](https://github.com/homarr-labs/homarr/commit/022fad92a9aa74c132c91c6e0a942c7d520eac88)) +* everyone group page throws error ([#1450](https://github.com/homarr-labs/homarr/issues/1450)) ([f3ebd6c](https://github.com/homarr-labs/homarr/commit/f3ebd6ccdf2d5964daf50f4b9221d2231a91855d)) +* external users can be added to groups manually ([#1540](https://github.com/homarr-labs/homarr/issues/1540)) ([32e6b8e](https://github.com/homarr-labs/homarr/commit/32e6b8ee45cac46cf71fd5c6cd71558c352b4097)) +* fetch timeout for external requests to small ([#881](https://github.com/homarr-labs/homarr/issues/881)) ([67dad45](https://github.com/homarr-labs/homarr/commit/67dad45214a0dcda9d79abb4c731b7705ceb7f2d)) +* fix binary conflicts for linux ([#1583](https://github.com/homarr-labs/homarr/issues/1583)) ([70ab294](https://github.com/homarr-labs/homarr/commit/70ab29454a53958676de33bb39b9be1ea613e135)) +* fix i18n-ally extension config ([#1462](https://github.com/homarr-labs/homarr/issues/1462)) ([4ba9e94](https://github.com/homarr-labs/homarr/commit/4ba9e94dd6f632492ed250ccc267f5ac72805290)) +* Fix typecheck, lint issues and errors brought to dnshole summary. ([#916](https://github.com/homarr-labs/homarr/issues/916)) ([0cec1db](https://github.com/homarr-labs/homarr/commit/0cec1dbb1743bbe2af03a006c24d3588d5a55d83)) +* github actor name for automatic approval wrong ([#943](https://github.com/homarr-labs/homarr/issues/943)) ([c833f2c](https://github.com/homarr-labs/homarr/commit/c833f2cbf2560919f5e2381678a46d2d8d649854)) +* gridstack not working ([#642](https://github.com/homarr-labs/homarr/issues/642)) ([2c1b52a](https://github.com/homarr-labs/homarr/commit/2c1b52aff95af95b2732c4e86af87fffdcbd6896)) +* groups can be created with empty names ([#1267](https://github.com/homarr-labs/homarr/issues/1267)) ([98cf214](https://github.com/homarr-labs/homarr/commit/98cf214aed9423dbf4e13982641d9e167de4171d)) +* Handle existing user when editing profile ([6e2bd0c](https://github.com/homarr-labs/homarr/commit/6e2bd0ce11697cdfd59500d506e68ac22ed38273)) +* hard to move iframe widget [#1075](https://github.com/homarr-labs/homarr/issues/1075) ([#1101](https://github.com/homarr-labs/homarr/issues/1101)) ([5e77221](https://github.com/homarr-labs/homarr/commit/5e772215a9a26f04fec25d3d983a86e8c53faf7c)) +* health-check widget sorting & last seen ([#1363](https://github.com/homarr-labs/homarr/issues/1363)) ([c37a0e3](https://github.com/homarr-labs/homarr/commit/c37a0e38d950ec24bd33a174a229ee20434fa6f9)) +* icon picker keyboard interactions ([#1666](https://github.com/homarr-labs/homarr/issues/1666)) ([82ec77d](https://github.com/homarr-labs/homarr/commit/82ec77d2dac9764d44417a4e486a099f89b5e39c)) +* icon picker suspense issue ([#1533](https://github.com/homarr-labs/homarr/issues/1533)) ([ecf299e](https://github.com/homarr-labs/homarr/commit/ecf299e03b5906a7f006397ef1df463a2c531468)) +* icon selector is a select not an autocomplete [#515](https://github.com/homarr-labs/homarr/issues/515) ([#675](https://github.com/homarr-labs/homarr/issues/675)) ([e957c6b](https://github.com/homarr-labs/homarr/commit/e957c6b601b1ed1172df8ee998a50a56e4b83f1f)) +* improve ping performance ([#1020](https://github.com/homarr-labs/homarr/issues/1020)) ([b81f5a2](https://github.com/homarr-labs/homarr/commit/b81f5a2ee349f1b8205a86d72d00c4a2e3470d1f)) +* inconsistent session cookie ([#1310](https://github.com/homarr-labs/homarr/issues/1310)) ([12105b3](https://github.com/homarr-labs/homarr/commit/12105b3b2935afec4f43aed05e4e5700986430ea)) +* indexer manager UI behaviour + class naming ([#1134](https://github.com/homarr-labs/homarr/issues/1134)) ([6d4d6ef](https://github.com/homarr-labs/homarr/commit/6d4d6efe3f575830d10e8d04d71b14dcda82223b)) +* insert limit of sqlite is smaller than amount of icons ([#1161](https://github.com/homarr-labs/homarr/issues/1161)) ([9eea8d4](https://github.com/homarr-labs/homarr/commit/9eea8d48e8bc0776d6074840a47c4b4c2ba38347)) +* integration actions hidden for full access users ([#1300](https://github.com/homarr-labs/homarr/issues/1300)) ([476fda2](https://github.com/homarr-labs/homarr/commit/476fda279db3a501a376b5b77eff2ae99b8a0225)) +* integration links in manage section do not work ([#441](https://github.com/homarr-labs/homarr/issues/441)) ([4b80b16](https://github.com/homarr-labs/homarr/commit/4b80b16b530af17649ef71ab9481574b3e9a0159)) +* issue with category removal and ready state ([#129](https://github.com/homarr-labs/homarr/issues/129)) ([1e414af](https://github.com/homarr-labs/homarr/commit/1e414af57c604770118a3fac59941bfaff0ab6db)) +* issue with color scheme in layout ([#1168](https://github.com/homarr-labs/homarr/issues/1168)) ([8f7ed05](https://github.com/homarr-labs/homarr/commit/8f7ed056c435a66d095cdfd43b6e893dfc7e6da3)) +* issues found in security audit ([#1668](https://github.com/homarr-labs/homarr/issues/1668)) ([922101d](https://github.com/homarr-labs/homarr/commit/922101dcbd0c512815b2cbb354cbab0fe80028c0)) +* it was possible to go to the create user page when credentials login disabled ([#1217](https://github.com/homarr-labs/homarr/issues/1217)) ([d63f6d2](https://github.com/homarr-labs/homarr/commit/d63f6d270f496053ae52bc3b9bfe484372c5b9d3)) +* items can not be placed in newly created dynamic section without saving ([#1513](https://github.com/homarr-labs/homarr/issues/1513)) ([73cb0b9](https://github.com/homarr-labs/homarr/commit/73cb0b99accfeb05c63c78ff227db1d5f23b99b2)) +* job translations ([#846](https://github.com/homarr-labs/homarr/issues/846)) ([43e4801](https://github.com/homarr-labs/homarr/commit/43e48010e5f1d7cf65ad779c8684a7b468e43688)) +* local websocket url wrong ([#1328](https://github.com/homarr-labs/homarr/issues/1328)) ([7572634](https://github.com/homarr-labs/homarr/commit/757263478036d01d8fdbabf3857bb6ebd59ba9af)) +* login before pushing image ([4836801](https://github.com/homarr-labs/homarr/commit/4836801004301375220e8181c5f14e56020312d2)) +* login with revalidate path and wrong preferences link ([#654](https://github.com/homarr-labs/homarr/issues/654)) ([8e4ba37](https://github.com/homarr-labs/homarr/commit/8e4ba37f94294577926ae6e668d50b2e151b2d35)) +* make oldmarr app schema less restrictive ([#1495](https://github.com/homarr-labs/homarr/issues/1495)) ([879aa11](https://github.com/homarr-labs/homarr/commit/879aa1152f8e9182c14775672cf371fdc639e223)) +* Manage banner animation hitch fix ([#826](https://github.com/homarr-labs/homarr/issues/826)) ([4e03e7f](https://github.com/homarr-labs/homarr/commit/4e03e7f49d931090636dea7ebed4a0bea9659177)) +* manage links wrong ([#754](https://github.com/homarr-labs/homarr/issues/754)) ([be71114](https://github.com/homarr-labs/homarr/commit/be711149f7d1ef82ab30e43209d6173f2520de57)) +* mantine react table style issue ([#508](https://github.com/homarr-labs/homarr/issues/508)) ([5723295](https://github.com/homarr-labs/homarr/commit/5723295856ae557a25db3b5782e6c4bea6b6c301)) +* mantine-react-table not localized [#333](https://github.com/homarr-labs/homarr/issues/333) ([#873](https://github.com/homarr-labs/homarr/issues/873)) ([4380aa9](https://github.com/homarr-labs/homarr/commit/4380aa9b3e8659bbb95f8d91e35bffc87c8e65c5)) +* matcher for translation middleware only supports en and de ([#1528](https://github.com/homarr-labs/homarr/issues/1528)) ([38143b6](https://github.com/homarr-labs/homarr/commit/38143b679e389633dbd27a2fede866c3696c583c)) +* memory leak caused by many unclosed redis subscriptions ([#750](https://github.com/homarr-labs/homarr/issues/750)) ([998615f](https://github.com/homarr-labs/homarr/commit/998615fc11cfcca1d1a51464550d599addb8e49f)) +* middleware fetch failed for docker container ([#1424](https://github.com/homarr-labs/homarr/issues/1424)) ([b7fc1ae](https://github.com/homarr-labs/homarr/commit/b7fc1ae4bb0aa03595d849d909b997c307dce26c)) +* missing breadcrumb translation, wrong spacing in user layout ([#872](https://github.com/homarr-labs/homarr/issues/872)) ([55a000a](https://github.com/homarr-labs/homarr/commit/55a000a7fc2b2c977af3f25d5196a464c6890745)) +* missing migration for default colorscheme change ([#1335](https://github.com/homarr-labs/homarr/issues/1335)) ([9c5972f](https://github.com/homarr-labs/homarr/commit/9c5972faf45a31ec379fe7a2fdd19548755d27ed)) +* missing translations for apps / integrations [#438](https://github.com/homarr-labs/homarr/issues/438) ([#674](https://github.com/homarr-labs/homarr/issues/674)) ([f358c33](https://github.com/homarr-labs/homarr/commit/f358c33bd37e581d7a3ce02f527eb499f8ae4b85)) +* modal transition not working ([#433](https://github.com/homarr-labs/homarr/issues/433)) ([b888fad](https://github.com/homarr-labs/homarr/commit/b888fad1fc288961f0582464392e3f12751e9146)) +* moving categories up and down is not working ([#1542](https://github.com/homarr-labs/homarr/issues/1542)) ([52d2a88](https://github.com/homarr-labs/homarr/commit/52d2a88b61a6ef8513560e8810bce6fa0867f0a6)) +* mysql migration not working ([#1138](https://github.com/homarr-labs/homarr/issues/1138)) ([003cc51](https://github.com/homarr-labs/homarr/commit/003cc5160c68d73e3cfbc3e933099a9275782b5b)) +* new sections without add and change listeners ([#1230](https://github.com/homarr-labs/homarr/issues/1230)) ([665df53](https://github.com/homarr-labs/homarr/commit/665df53a39cc90d4155b3c8436a88986aa7a5b23)) +* next auth host not trusted ([#144](https://github.com/homarr-labs/homarr/issues/144)) ([b2cee8f](https://github.com/homarr-labs/homarr/commit/b2cee8f6936d526072dd65a59a494081cfb81c16)) +* nextjs is slow dev server ([#364](https://github.com/homarr-labs/homarr/issues/364)) ([b78d32b](https://github.com/homarr-labs/homarr/commit/b78d32b81c6075a3d04abf0e8e7631e8ce6ef49c)) +* node cache cleanup error ([#1124](https://github.com/homarr-labs/homarr/issues/1124)) ([16a5b43](https://github.com/homarr-labs/homarr/commit/16a5b43695f5e8c8d3ba5ac9d1bfe2dec83f3bf1)) +* notebook save button on align buttons ([#1456](https://github.com/homarr-labs/homarr/issues/1456)) ([15abfbb](https://github.com/homarr-labs/homarr/commit/15abfbbdf722b9f996c69072b57105ecfdc647ad)) +* **notebook:** default-content image path ([#1244](https://github.com/homarr-labs/homarr/issues/1244)) ([b5bfe90](https://github.com/homarr-labs/homarr/commit/b5bfe90453b8ad5028b52b856631ec30f3f80afd)) +* open navigation item by default ([#716](https://github.com/homarr-labs/homarr/issues/716)) ([c4b54ed](https://github.com/homarr-labs/homarr/commit/c4b54ed36c2da54457ac58496e62e13856bc0c98)) +* open-api doc generation failing, post patch and delete not exported ([#1565](https://github.com/homarr-labs/homarr/issues/1565)) ([2d7efc3](https://github.com/homarr-labs/homarr/commit/2d7efc3ffacb16c27219c26f20fd0682304927e0)) +* overview in series of sonarr schema is optional ([#880](https://github.com/homarr-labs/homarr/issues/880)) ([406ed16](https://github.com/homarr-labs/homarr/commit/406ed16ce45683d04e7f0293037d1eeae269795d)) +* pass token to cli ([653f42b](https://github.com/homarr-labs/homarr/commit/653f42bccb8a5893eb64d66c4963068b37011cd7)) +* permissions not restricted for certain management pages / actions ([#1219](https://github.com/homarr-labs/homarr/issues/1219)) ([1421ccc](https://github.com/homarr-labs/homarr/commit/1421ccc917fc54a8afcf6ba700d4b0590fa90ed5)) +* ping urls are not reset when restarting ([#924](https://github.com/homarr-labs/homarr/issues/924)) ([365e267](https://github.com/homarr-labs/homarr/commit/365e267b8d7ba75e47af974dec6f427592095185)) +* pnpm dev did not work caused by tsx update ([#638](https://github.com/homarr-labs/homarr/issues/638)) ([fb92c3e](https://github.com/homarr-labs/homarr/commit/fb92c3e95c164b4297c74bbe18461cd08b003112)) +* prevent flickering by removing auto color scheme and default background color ([#1299](https://github.com/homarr-labs/homarr/issues/1299)) ([cd77acd](https://github.com/homarr-labs/homarr/commit/cd77acdfabf6f58aa1973e8db9408379801a8085)) +* rdb files can not be saved because of permission issues bug: redis can not save RDB files [#318](https://github.com/homarr-labs/homarr/issues/318) ([#472](https://github.com/homarr-labs/homarr/issues/472)) ([fd44ee4](https://github.com/homarr-labs/homarr/commit/fd44ee48f4dbd67a1f86a6a3fe7c7c986b87443a)) +* redirect url from login not working ([#952](https://github.com/homarr-labs/homarr/issues/952)) ([349c494](https://github.com/homarr-labs/homarr/commit/349c49462fdf29741910e036e4494909c13b6124)) +* remove unnecessary complex copy and build steps in dockerfile ([#1595](https://github.com/homarr-labs/homarr/issues/1595)) ([2686dad](https://github.com/homarr-labs/homarr/commit/2686dad63017cd3b8e45818bfcb27fa3618f1a15)) +* remove unused properties in SabNZBd schema ([#1415](https://github.com/homarr-labs/homarr/issues/1415)) ([ceafd37](https://github.com/homarr-labs/homarr/commit/ceafd3747b3a56531ca3357f68fd33350cf5c896)) +* Remove version override ([#67](https://github.com/homarr-labs/homarr/issues/67)) ([55ec600](https://github.com/homarr-labs/homarr/commit/55ec60041ac5fd38861220f42e6b6daba1fb3eb3)) +* rename default to home board ([#1538](https://github.com/homarr-labs/homarr/issues/1538)) ([1c4d4f4](https://github.com/homarr-labs/homarr/commit/1c4d4f4e9d39d52d6a8e69f06c1d6246c774ed79)) +* renovate approval run for all pull requests on every pull request change ([#942](https://github.com/homarr-labs/homarr/issues/942)) ([017c378](https://github.com/homarr-labs/homarr/commit/017c378582cca20688acac171bab803597d825b4)) +* renovate approval workflow not running ([#948](https://github.com/homarr-labs/homarr/issues/948)) ([ab7d3f8](https://github.com/homarr-labs/homarr/commit/ab7d3f8e4c82fcee9af6f79c70943633fec9af95)) +* renovate automatic approval typo no file extension ([#572](https://github.com/homarr-labs/homarr/issues/572)) ([c2185e3](https://github.com/homarr-labs/homarr/commit/c2185e34890b028eac7486a52d04967037be2183)) +* renovate config with json does not support comments ([#641](https://github.com/homarr-labs/homarr/issues/641)) ([e46ea71](https://github.com/homarr-labs/homarr/commit/e46ea71bc2f89f02403e8a9597dc02474181776d)) +* restrict access to docker containers page to admins ([#912](https://github.com/homarr-labs/homarr/issues/912)) ([b8b084c](https://github.com/homarr-labs/homarr/commit/b8b084c188b28ba8fb317156433e694e7d37dfbb)) +* revert mysql2 to version 3.9.2 as with 3.9.3 nextjs build fails ([1fc2df1](https://github.com/homarr-labs/homarr/commit/1fc2df19ec6e707f7dc9ca11e60f021dd03fc5aa)) +* rtl common translation unnecessary ([#1246](https://github.com/homarr-labs/homarr/issues/1246)) ([770768e](https://github.com/homarr-labs/homarr/commit/770768eb211259848437522615b7b78ecfca8ee5)) +* sensitive data can be leaked through query parameters ([#1208](https://github.com/homarr-labs/homarr/issues/1208)) ([f24c068](https://github.com/homarr-labs/homarr/commit/f24c06852e0bf6d672b58b784ce34d96581c2c03)) +* server data is loaded on settings page [#363](https://github.com/homarr-labs/homarr/issues/363) ([#414](https://github.com/homarr-labs/homarr/issues/414)) ([7c98b65](https://github.com/homarr-labs/homarr/commit/7c98b65401778a61a4af4206612fa62dd95ba9a5)) +* sessions from inactive providers can still be used ([#1458](https://github.com/homarr-labs/homarr/issues/1458)) ([1105f00](https://github.com/homarr-labs/homarr/commit/1105f0029fd1479e3ab6d8dae8524233c264ca21)) +* sharp is not installed ([#397](https://github.com/homarr-labs/homarr/issues/397)) ([5f24797](https://github.com/homarr-labs/homarr/commit/5f247977fa50405d5daed9f628d1170d15be412d)), closes [#320](https://github.com/homarr-labs/homarr/issues/320) +* specify step image version ([fa2c448](https://github.com/homarr-labs/homarr/commit/fa2c448bac9734662295cb8ebd62f733d3153be2)) +* **spotlight:** x button not clickable, help links open in current tab, bad screen usage on mobile ([#1199](https://github.com/homarr-labs/homarr/issues/1199)) ([42a49e6](https://github.com/homarr-labs/homarr/commit/42a49e6461f1834a1e54563e908fe75457de6d96)) +* styles for light mode ([#1645](https://github.com/homarr-labs/homarr/issues/1645)) ([cf9656d](https://github.com/homarr-labs/homarr/commit/cf9656d91eedc73224e9cfc8871c977988994425)) +* testConnectionAsync url ([#1024](https://github.com/homarr-labs/homarr/issues/1024)) ([e34af86](https://github.com/homarr-labs/homarr/commit/e34af8659b6562e1ec3ebc502eff52ef3c699654)) +* trailing slash integration url issues ([#1571](https://github.com/homarr-labs/homarr/issues/1571)) ([b277f44](https://github.com/homarr-labs/homarr/commit/b277f444b2c01e251b53069c17674eb4188b5f8d)) +* transfer group not invalidating path ([#1539](https://github.com/homarr-labs/homarr/issues/1539)) ([74e1b6b](https://github.com/homarr-labs/homarr/commit/74e1b6b54494455fecc37f673569482c3fad1ce4)) +* trpc error at least one integration ([#1660](https://github.com/homarr-labs/homarr/issues/1660)) ([f857105](https://github.com/homarr-labs/homarr/commit/f8571059941a4c13b9b8bca24b399ca06a8aa13f)) +* try using other variable ([5c68ac9](https://github.com/homarr-labs/homarr/commit/5c68ac9e2eda1c28befd25a14cc3c2b6e3965c34)) +* tsx not working ([#434](https://github.com/homarr-labs/homarr/issues/434)) ([5abd438](https://github.com/homarr-labs/homarr/commit/5abd438a494048738017a976faa35e1c79c7fd96)) +* typo in automatic release commit message ([#726](https://github.com/homarr-labs/homarr/issues/726)) ([8fc2884](https://github.com/homarr-labs/homarr/commit/8fc28844bbedb4edbdc504aba6330bad06d34e93)) +* typo in renovate config name ([#557](https://github.com/homarr-labs/homarr/issues/557)) ([4d1e4d5](https://github.com/homarr-labs/homarr/commit/4d1e4d55bc56a567aa5ae70a1c2d6bd7ed738954)) +* unable to select integration on board page ([#450](https://github.com/homarr-labs/homarr/issues/450)) ([c884644](https://github.com/homarr-labs/homarr/commit/c88464498fcca95232e87b684b20e932891b939c)) +* Update check for user existence ([65025a5](https://github.com/homarr-labs/homarr/commit/65025a5dda4414aa98ac042b64b22f15ddc8bff8)) +* use correct branch for tag compare ([0c7f479](https://github.com/homarr-labs/homarr/commit/0c7f47995211f31fa81d0f27b9a0d901dd2e422c)) +* user is undefined when using use-suspense-query ([#1498](https://github.com/homarr-labs/homarr/issues/1498)) ([18b579e](https://github.com/homarr-labs/homarr/commit/18b579eb5f2ce77ac19a2bd9fee9c99025ab1c2d)) +* various issues with docker image workflow ([#1172](https://github.com/homarr-labs/homarr/issues/1172)) ([d029f48](https://github.com/homarr-labs/homarr/commit/d029f48f799bc9ff7e01c4b85194b58e050f0c5b)) +* videos not playing automatically on iOS / mobile ([#875](https://github.com/homarr-labs/homarr/issues/875)) ([8e10c48](https://github.com/homarr-labs/homarr/commit/8e10c48d2f182b1f11baac8747a0701019a4387c)) +* websockets on https do not work ([#1444](https://github.com/homarr-labs/homarr/issues/1444)) ([0aa72d1](https://github.com/homarr-labs/homarr/commit/0aa72d118c6c61798cff3406256e4253d0ad5aab)) +* wevbsocket url is always localhost ([#1072](https://github.com/homarr-labs/homarr/issues/1072)) ([8c20553](https://github.com/homarr-labs/homarr/commit/8c205535eb2d2e3a6efb26696460f1c60c58170e)) +* when no dead icons, all icons are removed ([#516](https://github.com/homarr-labs/homarr/issues/516)) ([8e8f908](https://github.com/homarr-labs/homarr/commit/8e8f9081b029e8a01e4dcfcc14e6cd259732c519)) +* when removing one item and then adding another one that newly added one can not be moved ([#1025](https://github.com/homarr-labs/homarr/issues/1025)) ([2738f40](https://github.com/homarr-labs/homarr/commit/2738f40c5e3028822c4586556fddc16af5aa7d58)) +* workflow inputs and docker push ([#1123](https://github.com/homarr-labs/homarr/issues/1123)) ([c8dfbc8](https://github.com/homarr-labs/homarr/commit/c8dfbc8e2d3fd50958b124bdc4e1ad6b0af8f7ca)) +* wrong id for renovate auto approval ([#957](https://github.com/homarr-labs/homarr/issues/957)) ([67195c6](https://github.com/homarr-labs/homarr/commit/67195c605139dfd4b3cd1e7d7e627752e71a7f1f)) +* xterm-addon-fit deprecated ([#321](https://github.com/homarr-labs/homarr/issues/321)) ([e6e6e4e](https://github.com/homarr-labs/homarr/commit/e6e6e4e7d639277c6b23d389721de81f7abd68d0)) + +### Performance Improvements + +* improve performance of icon updater from 10s to 300ms ([#502](https://github.com/homarr-labs/homarr/issues/502)) ([333dc57](https://github.com/homarr-labs/homarr/commit/333dc571fa32e9aad988f91b2547cebd99388fb4)) +* improve typescript performance ([#523](https://github.com/homarr-labs/homarr/issues/523)) ([d9f5158](https://github.com/homarr-labs/homarr/commit/d9f5158662e55bcfcb8a33018f3826286df8ff8c)) diff --git a/Dockerfile b/Dockerfile index 443a7ce08..59d40428f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:22.12.0-alpine AS base +FROM node:22.13.0-alpine AS base FROM base AS builder RUN apk add --no-cache libc6-compat @@ -12,9 +12,6 @@ COPY . . RUN corepack enable pnpm && pnpm install --recursive --frozen-lockfile -# Install sharp for image optimization -RUN corepack enable pnpm && pnpm install sharp -w - # Copy static data as it is not part of the build COPY static-data ./static-data ARG SKIP_ENV_VALIDATION='true' @@ -25,51 +22,41 @@ RUN corepack enable pnpm && pnpm build FROM base AS runner WORKDIR /app -# gettext is required for envsubst -RUN apk add --no-cache redis nginx bash gettext +# gettext is required for envsubst, openssl for generating AUTH_SECRET, su-exec for running application as non-root +RUN apk add --no-cache redis nginx bash gettext su-exec openssl RUN mkdir /appdata VOLUME /appdata -RUN mkdir /secrets -VOLUME /secrets - - - -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 nextjs # Enable homarr cli -COPY --from=builder --chown=nextjs:nodejs /app/packages/cli/cli.cjs /app/apps/cli/cli.cjs +COPY --from=builder /app/packages/cli/cli.cjs /app/apps/cli/cli.cjs RUN echo $'#!/bin/bash\ncd /app/apps/cli && node ./cli.cjs "$@"' > /usr/bin/homarr RUN chmod +x /usr/bin/homarr # Don't run production as root -RUN chown -R nextjs:nodejs /appdata -RUN chown -R nextjs:nodejs /secrets -RUN mkdir -p /var/cache/nginx && chown -R nextjs:nodejs /var/cache/nginx && \ - mkdir -p /var/log/nginx && chown -R nextjs:nodejs /var/log/nginx && \ - mkdir -p /var/lib/nginx && chown -R nextjs:nodejs /var/lib/nginx && \ - touch /run/nginx/nginx.pid && chown -R nextjs:nodejs /run/nginx/nginx.pid && \ - mkdir -p /etc/nginx/templates /etc/nginx/ssl/certs && chown -R nextjs:nodejs /etc/nginx -USER nextjs +RUN mkdir -p /var/cache/nginx && \ + mkdir -p /var/log/nginx && \ + mkdir -p /var/lib/nginx && \ + touch /run/nginx/nginx.pid && \ + mkdir -p /etc/nginx/templates /etc/nginx/ssl/certs -COPY --from=builder /app/apps/nextjs/next.config.mjs . +COPY --from=builder /app/apps/nextjs/next.config.ts . COPY --from=builder /app/apps/nextjs/package.json . -COPY --from=builder --chown=nextjs:nodejs /app/apps/tasks/tasks.cjs ./apps/tasks/tasks.cjs -COPY --from=builder --chown=nextjs:nodejs /app/apps/websocket/wssServer.cjs ./apps/websocket/wssServer.cjs -COPY --from=builder --chown=nextjs:nodejs /app/node_modules/better-sqlite3/build/Release/better_sqlite3.node /app/build/better_sqlite3.node +COPY --from=builder /app/apps/tasks/tasks.cjs ./apps/tasks/tasks.cjs +COPY --from=builder /app/apps/websocket/wssServer.cjs ./apps/websocket/wssServer.cjs +COPY --from=builder /app/node_modules/better-sqlite3/build/Release/better_sqlite3.node /app/build/better_sqlite3.node -COPY --from=builder --chown=nextjs:nodejs /app/packages/db/migrations ./db/migrations +COPY --from=builder /app/packages/db/migrations ./db/migrations # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=builder --chown=nextjs:nodejs /app/apps/nextjs/.next/standalone ./ -COPY --from=builder --chown=nextjs:nodejs /app/apps/nextjs/.next/static ./apps/nextjs/.next/static -COPY --from=builder --chown=nextjs:nodejs /app/apps/nextjs/public ./apps/nextjs/public -COPY --chown=nextjs:nodejs scripts/run.sh ./run.sh -COPY --chown=nextjs:nodejs scripts/generateEncryptionKey.js ./generateEncryptionKey.js -COPY --chown=nextjs:nodejs packages/redis/redis.conf /app/redis.conf -COPY --chown=nextjs:nodejs nginx.conf /etc/nginx/templates/nginx.conf +COPY --from=builder /app/apps/nextjs/.next/standalone ./ +COPY --from=builder /app/apps/nextjs/.next/static ./apps/nextjs/.next/static +COPY --from=builder /app/apps/nextjs/public ./apps/nextjs/public +COPY scripts/run.sh ./run.sh +COPY --chmod=777 scripts/entrypoint.sh ./entrypoint.sh +COPY packages/redis/redis.conf /app/redis.conf +COPY nginx.conf /etc/nginx/templates/nginx.conf ENV DB_URL='/appdata/db/db.sqlite' @@ -77,4 +64,5 @@ ENV DB_DIALECT='sqlite' ENV DB_DRIVER='better-sqlite3' ENV AUTH_PROVIDERS='credentials' -CMD ["sh", "run.sh"] +ENTRYPOINT [ "/app/entrypoint.sh" ] +CMD ["sh", "run.sh"] \ No newline at end of file diff --git a/LICENSE b/LICENSE index 435503eb6..46fa751ae 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,201 @@ -MIT License + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Copyright (c) 2023 Julius Marminge + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + 1. Definitions. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2024 Meier Lukas, Thomas Camlong and Homarr Labs + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md deleted file mode 100644 index 3a88af411..000000000 --- a/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# THIS PROJECT IS STILL UNSTABLE AND WE DO NOT PROVIDE ANY SUPPORT FOR ISSUES THAT OCCURE. - -## PLEASE DO NOT OPEN ANY ISSUES OR DISCUSSIONS - -### EVERYTHING IS SUBJECT TO CHANGE - -Please use [this](https://github.com/ajnart/homarr) version of Homarr when you want to use it diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..493565dc0 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,29 @@ +# Security Policy +This policy is relevant if you found potential vulnerabilities in an audit. +We consider something as a vulnerability if it... +1. puts users or user data at risk +2. enables third parties to gain control or access (e.g. [RATs](https://en.wikipedia.org/wiki/Remote_desktop_software#RAT), [privilege escalation](https://en.wikipedia.org/wiki/Privilege_escalation), ...) +3. abuses the system in an unintended way (e.g. crypto mining, proxy, ...) + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| >1.0.0 | :white_check_mark: | +| <1.0.0 | :x: | + +## Reporting a Vulnerability +We use [GitHub's system for reporting vulnerabilities](https://docs.github.com/en/enterprise-cloud@latest/code-security/security-advisories/working-with-repository-security-advisories/creating-a-repository-security-advisory). +Click [**here to report an advisory**](https://github.com/homarr-labs/homarr/security/advisories/new). Our team will get notified and will get back to you within 1-6 business days. + +As a general guideline; please provide as much detail as possible and provide reproduction steps / documentation regarding the re-creation. +You may also provide a fork with a fix for the vulnerability. +See https://cheatsheetseries.owasp.org/cheatsheets/Vulnerability_Disclosure_Cheat_Sheet.html for guidelines regarding disclosure. + +If you're unable / unwilling (or it's not safe) to disclose vulnerabilites via GitHub, please report them with the subject "Security advisory - CVEXXX" to our email homarr-labs@proton.me. +Please never disclose security vulnerabilits on your own publicly - we'd like to search for a dimplomatic solution that is also safe for our users. + +In your initial contact with us, please provide details according to the [OWASP guidelines for initial reports](https://cheatsheetseries.owasp.org/cheatsheets/Vulnerability_Disclosure_Cheat_Sheet.html#initial-report). + +Thank you! +We're looking forward to your report diff --git a/apps/nextjs/next.config.mjs b/apps/nextjs/next.config.ts similarity index 74% rename from apps/nextjs/next.config.mjs rename to apps/nextjs/next.config.ts index 2467471d8..5a082309c 100644 --- a/apps/nextjs/next.config.mjs +++ b/apps/nextjs/next.config.ts @@ -1,22 +1,33 @@ // Importing env files here to validate on build -import "@homarr/auth/env.mjs"; +import "@homarr/auth/env"; +import "@homarr/db/env"; +import "@homarr/common/env"; +import type { NextConfig } from "next"; import MillionLint from "@million/lint"; import createNextIntlPlugin from "next-intl/plugin"; -import "./src/env.mjs"; +import "./src/env.ts"; // Package path does not work... so we need to use relative path const withNextIntl = createNextIntlPlugin("../../packages/translation/src/request.ts"); -/** @type {import("next").NextConfig} */ -const nextConfig = { +interface WebpackConfig { + module: { + rules: { + test: RegExp; + loader: string; + }[]; + }; +} + +const nextConfig: NextConfig = { output: "standalone", reactStrictMode: true, /** We already do linting and typechecking as separate tasks in CI */ eslint: { ignoreDuringBuilds: true }, typescript: { ignoreBuildErrors: true }, - webpack: (config, { isServer }) => { + webpack: (config: WebpackConfig, { isServer }) => { if (isServer) { config.module.rules.push({ test: /\.node$/, @@ -36,6 +47,7 @@ const nextConfig = { }; // Skip transform is used because of webpack loader, without it for example 'Tooltip.Floating' will not work and show an error +// eslint-disable-next-line @typescript-eslint/no-unused-vars const withMillionLint = MillionLint.next({ rsc: true, skipTransform: true, telemetry: false }); export default withNextIntl(nextConfig); diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index 4651866da..66d6e42d8 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "pnpm with-env next build", "clean": "git clean -xdf .next .turbo node_modules", - "dev": "pnpm with-env next dev", + "dev": "pnpm with-env next dev --turbopack", "format": "prettier --check . --ignore-path ../../.gitignore", "lint": "eslint", "start": "pnpm with-env next start", @@ -18,17 +18,19 @@ "@homarr/analytics": "workspace:^0.1.0", "@homarr/api": "workspace:^0.1.0", "@homarr/auth": "workspace:^0.1.0", + "@homarr/certificates": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0", "@homarr/cron-job-status": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", "@homarr/form": "workspace:^0.1.0", - "@homarr/gridstack": "^1.11.2", + "@homarr/gridstack": "^1.11.3", "@homarr/integrations": "workspace:^0.1.0", "@homarr/log": "workspace:^", "@homarr/modals": "workspace:^0.1.0", "@homarr/modals-collection": "workspace:^0.1.0", "@homarr/notifications": "workspace:^0.1.0", + "@homarr/old-import": "workspace:^0.1.0", "@homarr/old-schema": "workspace:^0.1.0", "@homarr/redis": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0", @@ -37,17 +39,18 @@ "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", "@homarr/widgets": "workspace:^0.1.0", - "@mantine/colors-generator": "^7.15.1", - "@mantine/core": "^7.15.1", - "@mantine/hooks": "^7.15.1", - "@mantine/modals": "^7.15.1", - "@mantine/tiptap": "^7.15.1", + "@mantine/colors-generator": "^7.16.0", + "@mantine/core": "^7.16.0", + "@mantine/dropzone": "^7.16.0", + "@mantine/hooks": "^7.16.0", + "@mantine/modals": "^7.16.0", + "@mantine/tiptap": "^7.16.0", "@million/lint": "1.0.14", "@t3-oss/env-nextjs": "^0.11.1", - "@tabler/icons-react": "^3.24.0", - "@tanstack/react-query": "^5.62.7", - "@tanstack/react-query-devtools": "^5.62.7", - "@tanstack/react-query-next-experimental": "5.62.7", + "@tabler/icons-react": "^3.28.1", + "@tanstack/react-query": "^5.64.1", + "@tanstack/react-query-devtools": "^5.64.1", + "@tanstack/react-query-next-experimental": "5.64.1", "@trpc/client": "next", "@trpc/next": "next", "@trpc/react-query": "next", @@ -59,18 +62,18 @@ "clsx": "^2.1.1", "dayjs": "^1.11.13", "dotenv": "^16.4.7", - "flag-icons": "^7.2.3", - "glob": "^11.0.0", - "jotai": "^2.10.3", - "mantine-react-table": "2.0.0-beta.7", - "next": "^14.2.20", + "flag-icons": "^7.3.1", + "glob": "^11.0.1", + "jotai": "^2.11.0", + "mantine-react-table": "2.0.0-beta.8", + "next": "15.1.4", "postcss-preset-mantine": "^1.17.0", "prismjs": "^1.29.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "react-error-boundary": "^4.1.2", + "react": "19.0.0", + "react-dom": "19.0.0", + "react-error-boundary": "^5.0.0", "react-simple-code-editor": "^0.14.1", - "sass": "^1.83.0", + "sass": "^1.83.4", "superjson": "2.2.2", "swagger-ui-react": "^5.18.2", "use-deep-compare-effect": "^1.8.1" @@ -79,16 +82,16 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "@types/chroma-js": "2.4.4", - "@types/node": "^22.10.2", + "@types/chroma-js": "3.1.0", + "@types/node": "^22.10.7", "@types/prismjs": "^1.26.5", - "@types/react": "^19.0.1", - "@types/react-dom": "^19.0.2", + "@types/react": "19.0.7", + "@types/react-dom": "19.0.3", "@types/swagger-ui-react": "^4.18.3", - "concurrently": "^9.1.0", - "eslint": "^9.16.0", + "concurrently": "^9.1.2", + "eslint": "^9.18.0", "node-loader": "^2.1.0", "prettier": "^3.4.2", - "typescript": "^5.7.2" + "typescript": "^5.7.3" } } diff --git a/apps/nextjs/src/app/[locale]/(home)/(board)/layout.tsx b/apps/nextjs/src/app/[locale]/(home)/(board)/layout.tsx new file mode 100644 index 000000000..3467dc941 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/(home)/(board)/layout.tsx @@ -0,0 +1,5 @@ +import definition from "../../boards/(content)/(home)/_definition"; + +const { layout } = definition; + +export default layout; diff --git a/apps/nextjs/src/app/[locale]/(home-board)/page.tsx b/apps/nextjs/src/app/[locale]/(home)/(board)/page.tsx similarity index 64% rename from apps/nextjs/src/app/[locale]/(home-board)/page.tsx rename to apps/nextjs/src/app/[locale]/(home)/(board)/page.tsx index 7554444e5..79d1685df 100644 --- a/apps/nextjs/src/app/[locale]/(home-board)/page.tsx +++ b/apps/nextjs/src/app/[locale]/(home)/(board)/page.tsx @@ -1,4 +1,4 @@ -import definition from "../boards/(content)/(home)/_definition"; +import definition from "../../boards/(content)/(home)/_definition"; const { generateMetadataAsync: generateMetadata, page } = definition; diff --git a/apps/nextjs/src/app/[locale]/(home)/not-found.tsx b/apps/nextjs/src/app/[locale]/(home)/not-found.tsx new file mode 100644 index 000000000..b88f6c393 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/(home)/not-found.tsx @@ -0,0 +1,3 @@ +import HomeBoardNotFoundPage from "../boards/(content)/not-found"; + +export default HomeBoardNotFoundPage; diff --git a/apps/nextjs/src/app/[locale]/(home-board)/layout.tsx b/apps/nextjs/src/app/[locale]/(home-board)/layout.tsx deleted file mode 100644 index 9b69474ba..000000000 --- a/apps/nextjs/src/app/[locale]/(home-board)/layout.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import definition from "../boards/(content)/(home)/_definition"; - -const { layout } = definition; - -export default layout; diff --git a/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx b/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx index 8a2e6c581..3d2042030 100644 --- a/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx +++ b/apps/nextjs/src/app/[locale]/_client-providers/trpc.tsx @@ -15,11 +15,13 @@ import { wsLink, } from "@trpc/client"; import superjson from "superjson"; +import type { SuperJSONResult } from "superjson"; import type { AppRouter } from "@homarr/api"; -import { clientApi, createHeadersCallbackForSource, getTrpcUrl } from "@homarr/api/client"; +import { clientApi, getTrpcUrl } from "@homarr/api/client"; +import { createHeadersCallbackForSource } from "@homarr/api/shared"; -import { env } from "~/env.mjs"; +import { env } from "~/env"; const getWebSocketProtocol = () => { // window is not defined on server side @@ -82,8 +84,8 @@ export function TRPCReactProvider(props: PropsWithChildren) { serialize(object: unknown) { return object; }, - deserialize(data: unknown) { - return data; + deserialize(data: SuperJSONResult) { + return superjson.deserialize(data); }, }, url: getTrpcUrl(), diff --git a/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx b/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx index 1624b50b5..7de11ff0f 100644 --- a/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx +++ b/apps/nextjs/src/app/[locale]/auth/invite/[id]/page.tsx @@ -4,22 +4,24 @@ import { Card, Center, Stack, Text, Title } from "@mantine/core"; import { auth } from "@homarr/auth/next"; import { isProviderEnabled } from "@homarr/auth/server"; import { and, db, eq } from "@homarr/db"; -import { invites } from "@homarr/db/schema/sqlite"; +import { invites } from "@homarr/db/schema"; import { getScopedI18n } from "@homarr/translation/server"; import { HomarrLogoWithTitle } from "~/components/layout/logo/homarr-logo"; import { RegistrationForm } from "./_registration-form"; interface InviteUsagePageProps { - params: { + params: Promise<{ id: string; - }; - searchParams: { + }>; + searchParams: Promise<{ token: string; - }; + }>; } -export default async function InviteUsagePage({ params, searchParams }: InviteUsagePageProps) { +export default async function InviteUsagePage(props: InviteUsagePageProps) { + const searchParams = await props.searchParams; + const params = await props.params; if (!isProviderEnabled("credentials")) notFound(); const session = await auth(); @@ -57,7 +59,7 @@ export default async function InviteUsagePage({ params, searchParams }: InviteUs {t("subtitle")} - + diff --git a/apps/nextjs/src/app/[locale]/auth/login/page.tsx b/apps/nextjs/src/app/[locale]/auth/login/page.tsx index fb8472bd4..c9d913c08 100644 --- a/apps/nextjs/src/app/[locale]/auth/login/page.tsx +++ b/apps/nextjs/src/app/[locale]/auth/login/page.tsx @@ -1,7 +1,7 @@ import { redirect } from "next/navigation"; import { Card, Center, Stack, Text, Title } from "@mantine/core"; -import { env } from "@homarr/auth/env.mjs"; +import { env } from "@homarr/auth/env"; import { auth } from "@homarr/auth/next"; import { getScopedI18n } from "@homarr/translation/server"; @@ -9,12 +9,13 @@ import { HomarrLogoWithTitle } from "~/components/layout/logo/homarr-logo"; import { LoginForm } from "./_login-form"; interface LoginProps { - searchParams: { + searchParams: Promise<{ callbackUrl?: string; - }; + }>; } -export default async function Login({ searchParams }: LoginProps) { +export default async function Login(props: LoginProps) { + const searchParams = await props.searchParams; const session = await auth(); if (session) { @@ -35,7 +36,7 @@ export default async function Login({ searchParams }: LoginProps) { {t("subtitle")} - + ({ async getInitialBoardAsync({ name }) { diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/[name]/layout.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/[name]/(board)/layout.tsx similarity index 100% rename from apps/nextjs/src/app/[locale]/boards/(content)/[name]/layout.tsx rename to apps/nextjs/src/app/[locale]/boards/(content)/[name]/(board)/layout.tsx diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/[name]/page.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/[name]/(board)/page.tsx similarity index 100% rename from apps/nextjs/src/app/[locale]/boards/(content)/[name]/page.tsx rename to apps/nextjs/src/app/[locale]/boards/(content)/[name]/(board)/page.tsx diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/[name]/not-found.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/[name]/not-found.tsx new file mode 100644 index 000000000..9c398669b --- /dev/null +++ b/apps/nextjs/src/app/[locale]/boards/(content)/[name]/not-found.tsx @@ -0,0 +1,18 @@ +import { IconLayoutOff } from "@tabler/icons-react"; + +import { getScopedI18n } from "@homarr/translation/server"; + +import { BoardNotFound } from "~/components/board/not-found"; + +export default async function BoardNotFoundPage() { + const tNotFound = await getScopedI18n("board.error.notFound"); + return ( + + ); +} diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx index e951a4318..b0657e1e1 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx +++ b/apps/nextjs/src/app/[locale]/boards/(content)/_header-actions.tsx @@ -28,7 +28,7 @@ import { useCategoryActions } from "~/components/board/sections/category/categor import { CategoryEditModal } from "~/components/board/sections/category/category-edit-modal"; import { useDynamicSectionActions } from "~/components/board/sections/dynamic/dynamic-actions"; import { HeaderButton } from "~/components/layout/header/button"; -import { env } from "~/env.mjs"; +import { env } from "~/env"; import { useEditMode, useRequiredBoard } from "./_context"; export const BoardContentHeaderActions = () => { diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/not-found.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/not-found.tsx new file mode 100644 index 000000000..5ab6c8c61 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/boards/(content)/not-found.tsx @@ -0,0 +1,47 @@ +import { IconHomeOff } from "@tabler/icons-react"; + +import { auth } from "@homarr/auth/next"; +import { db } from "@homarr/db"; +import { boards } from "@homarr/db/schema"; +import { getI18n } from "@homarr/translation/server"; + +import type { BoardNotFoundProps } from "~/components/board/not-found"; +import { BoardNotFound } from "~/components/board/not-found"; + +export default async function NotFoundBoardHomePage() { + const boardNotFoundProps = await getPropsAsync(); + + return ; +} + +const getPropsAsync = async (): Promise => { + const boardCount = await db.$count(boards); + const t = await getI18n(); + + if (boardCount === 0) { + return { + icon: { src: "/favicon.ico", alt: "Homarr logo" }, + title: t("board.error.noBoard.title"), + description: t("board.error.noBoard.description"), + link: { label: t("board.error.noBoard.link"), href: "/manage/boards" }, + notice: t("board.error.noBoard.notice"), + }; + } + + const session = await auth(); + const isAdmin = session?.user.permissions.includes("admin"); + const type = isAdmin ? "admin" : session !== null ? "user" : "anonymous"; + const href = { + admin: "/manage/settings", + user: `/manage/users/${session?.user.id}/general`, + anonymous: "/manage/boards", + }[type]; + + return { + icon: IconHomeOff, + title: t(`board.error.homeBoard.title`), + description: t(`board.error.homeBoard.${type}.description`), + link: { label: t(`board.error.homeBoard.${type}.link`), href }, + notice: t(`board.error.homeBoard.${type}.notice`), + }; +}; diff --git a/apps/nextjs/src/app/[locale]/boards/[name]/settings/page.tsx b/apps/nextjs/src/app/[locale]/boards/[name]/settings/page.tsx index 06255e0ff..1ffb892d1 100644 --- a/apps/nextjs/src/app/[locale]/boards/[name]/settings/page.tsx +++ b/apps/nextjs/src/app/[locale]/boards/[name]/settings/page.tsx @@ -31,15 +31,15 @@ import { GeneralSettingsContent } from "./_general"; import { LayoutSettingsContent } from "./_layout"; interface Props { - params: { + params: Promise<{ name: string; - }; - searchParams: { + }>; + searchParams: Promise<{ tab?: keyof TranslationObject["board"]["setting"]["section"]; - }; + }>; } -const getBoardAndPermissionsAsync = async (params: Props["params"]) => { +const getBoardAndPermissionsAsync = async (params: Awaited) => { try { const board = await api.board.getBoardByName({ name: params.name }); const { hasFullAccess } = await getBoardPermissionsAsync(board); @@ -63,12 +63,18 @@ const getBoardAndPermissionsAsync = async (params: Props["params"]) => { } }; -export default async function BoardSettingsPage({ params, searchParams }: Props) { +export default async function BoardSettingsPage(props: Props) { + const searchParams = await props.searchParams; + const params = await props.params; const { board, permissions } = await getBoardAndPermissionsAsync(params); const boardSettings = await getServerSettingByKeyAsync(db, "board"); - const { hasFullAccess } = await getBoardPermissionsAsync(board); + const { hasFullAccess, hasChangeAccess } = await getBoardPermissionsAsync(board); const t = await getScopedI18n("board.setting"); + if (!hasChangeAccess) { + notFound(); + } + return ( @@ -95,7 +101,11 @@ export default async function BoardSettingsPage({ params, searchParams }: Props) - + )} diff --git a/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx b/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx index 9172515b9..22a4e53c0 100644 --- a/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx +++ b/apps/nextjs/src/app/[locale]/boards/_layout-creator.tsx @@ -28,9 +28,9 @@ export const createBoardLayout = ({ params, children, }: PropsWithChildren<{ - params: TParams; + params: Promise; }>) => { - const initialBoard = await getInitialBoard(params).catch((error) => { + const initialBoard = await getInitialBoard(await params).catch((error) => { if (error instanceof TRPCError && error.code === "NOT_FOUND") { logger.warn(error); notFound(); diff --git a/apps/nextjs/src/app/[locale]/init/_steps/back.tsx b/apps/nextjs/src/app/[locale]/init/_steps/back.tsx new file mode 100644 index 000000000..7fa98d283 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_steps/back.tsx @@ -0,0 +1,23 @@ +"use client"; + +import { Button } from "@mantine/core"; + +import { clientApi } from "@homarr/api/client"; +import { revalidatePathActionAsync } from "@homarr/common/client"; +import { useI18n } from "@homarr/translation/client"; + +export const BackToStart = () => { + const t = useI18n(); + const { mutateAsync, isPending } = clientApi.onboard.previousStep.useMutation(); + + const handleBackToStartAsync = async () => { + await mutateAsync(); + await revalidatePathActionAsync("/init"); + }; + + return ( + + ); +}; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/finish/init-finish.tsx b/apps/nextjs/src/app/[locale]/init/_steps/finish/init-finish.tsx new file mode 100644 index 000000000..d60da53ab --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_steps/finish/init-finish.tsx @@ -0,0 +1,87 @@ +import Link from "next/link"; +import type { MantineColor } from "@mantine/core"; +import { Button, Card, Stack, Text } from "@mantine/core"; +import { IconBook2, IconCategoryPlus, IconLayoutDashboard, IconMailForward } from "@tabler/icons-react"; + +import { isProviderEnabled } from "@homarr/auth/server"; +import { getMantineColor } from "@homarr/common"; +import { db } from "@homarr/db"; +import { createDocumentationLink } from "@homarr/definitions"; +import { getScopedI18n } from "@homarr/translation/server"; +import type { TablerIcon } from "@homarr/ui"; + +export const InitFinish = async () => { + const firstBoard = await db.query.boards.findFirst({ columns: { name: true } }); + const tFinish = await getScopedI18n("init.step.finish"); + + return ( + + + {tFinish("description")} + + {firstBoard ? ( + + {tFinish("action.goToBoard", { name: firstBoard.name })} + + ) : ( + + {tFinish("action.createBoard")} + + )} + + {isProviderEnabled("credentials") && ( + + {tFinish("action.inviteUser")} + + )} + + + {tFinish("action.docs")} + + + + ); +}; + +interface LinkButtonProps { + href: string; + children: string; + iconProps: IconProps; +} + +interface IconProps { + icon: TablerIcon; + color: MantineColor; +} + +const Icon = ({ icon: IcomComponent, color }: IconProps) => { + return ; +}; + +const InternalLinkButton = ({ href, children, iconProps }: LinkButtonProps) => { + return ( + + ); +}; + +const ExternalLinkButton = ({ href, children, iconProps }: LinkButtonProps) => { + return ( + + ); +}; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx b/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx new file mode 100644 index 000000000..93839a457 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_steps/group/init-group.tsx @@ -0,0 +1,52 @@ +"use client"; + +import { Button, Card, Stack, TextInput } from "@mantine/core"; +import { IconArrowRight } from "@tabler/icons-react"; + +import { clientApi } from "@homarr/api/client"; +import { revalidatePathActionAsync } from "@homarr/common/client"; +import { useZodForm } from "@homarr/form"; +import { useI18n } from "@homarr/translation/client"; +import type { z } from "@homarr/validation"; +import { validation } from "@homarr/validation"; + +export const InitGroup = () => { + const t = useI18n(); + const { mutateAsync } = clientApi.group.createInitialExternalGroup.useMutation(); + const form = useZodForm(validation.group.create, { + initialValues: { + name: "", + }, + }); + + const handleSubmitAsync = async (values: z.infer) => { + await mutateAsync(values, { + async onSuccess() { + await revalidatePathActionAsync("/init"); + }, + onError(error) { + if (error.data?.code === "CONFLICT") { + form.setErrors({ name: t("common.zod.errors.custom.groupNameTaken") }); + } + }, + }); + }; + + return ( + +
+ + + + +
+
+ ); +}; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/import/file-info-card.tsx b/apps/nextjs/src/app/[locale]/init/_steps/import/file-info-card.tsx new file mode 100644 index 000000000..7c031ae15 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_steps/import/file-info-card.tsx @@ -0,0 +1,41 @@ +import { ActionIcon, Button, Card, Group, Text } from "@mantine/core"; +import type { FileWithPath } from "@mantine/dropzone"; +import { IconPencil } from "@tabler/icons-react"; + +import { humanFileSize } from "@homarr/common"; +import { useScopedI18n } from "@homarr/translation/client"; + +interface FileInfoCardProps { + file: FileWithPath; + onRemove: () => void; +} + +export const FileInfoCard = ({ file, onRemove }: FileInfoCardProps) => { + const tFileInfo = useScopedI18n("init.step.import.fileInfo"); + return ( + + + + + {file.name} + + + {humanFileSize(file.size)} + + + + + + + + + ); +}; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/import/import-dropzone.tsx b/apps/nextjs/src/app/[locale]/init/_steps/import/import-dropzone.tsx new file mode 100644 index 000000000..cea43cabe --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_steps/import/import-dropzone.tsx @@ -0,0 +1,63 @@ +import { Group, rem, Text } from "@mantine/core"; +import type { FileWithPath } from "@mantine/dropzone"; +import { Dropzone, MIME_TYPES } from "@mantine/dropzone"; +import { IconFileZip, IconUpload, IconX } from "@tabler/icons-react"; + +import "@mantine/dropzone/styles.css"; + +import { useScopedI18n } from "@homarr/translation/client"; + +interface ImportDropZoneProps { + loading: boolean; + updateFile: (file: FileWithPath) => void; +} + +export const ImportDropZone = ({ loading, updateFile }: ImportDropZoneProps) => { + const tDropzone = useScopedI18n("init.step.import.dropzone"); + return ( + { + const firstFile = files[0]; + if (!firstFile) return; + + updateFile(firstFile); + }} + acceptColor="blue.6" + rejectColor="red.6" + accept={[MIME_TYPES.zip, "application/x-zip-compressed"]} + loading={loading} + multiple={false} + maxSize={1024 * 1024 * 1024 * 64} // 64 MB + onReject={(rejections) => { + console.error( + "Rejected files", + rejections.map( + (rejection) => + `File: ${rejection.file.name} size=${rejection.file.size} fileType=${rejection.file.type}\n - ${rejection.errors.map((error) => error.message).join("\n - ")}`, + ), + ); + }} + > + + + + + + + + + + + +
+ + {tDropzone("title")} + + + {tDropzone("description")} + +
+
+
+ ); +}; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/import/init-import.tsx b/apps/nextjs/src/app/[locale]/init/_steps/import/init-import.tsx new file mode 100644 index 000000000..8b7124a03 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_steps/import/init-import.tsx @@ -0,0 +1,53 @@ +"use client"; + +import { startTransition, useState } from "react"; +import { Card, Stack } from "@mantine/core"; +import type { FileWithPath } from "@mantine/dropzone"; + +import type { RouterOutputs } from "@homarr/api"; +import { clientApi } from "@homarr/api/client"; +import { InitialOldmarrImport } from "@homarr/old-import/components"; + +import { FileInfoCard } from "./file-info-card"; +import { ImportDropZone } from "./import-dropzone"; + +export const InitImport = () => { + const [file, setFile] = useState(null); + const { isPending, mutate } = clientApi.import.analyseInitialOldmarrImport.useMutation(); + const [analyseResult, setAnalyseResult] = useState( + null, + ); + + if (!file) { + return ( + + { + const formData = new FormData(); + formData.append("file", file); + + mutate(formData, { + onSuccess: (result) => { + startTransition(() => { + setAnalyseResult(result); + setFile(file); + }); + }, + onError: (error) => { + console.error(error); + }, + }); + }} + /> + + ); + } + + return ( + + setFile(null)} /> + {analyseResult !== null && } + + ); +}; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx b/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx new file mode 100644 index 000000000..90e8c7a8d --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_steps/settings/init-settings.tsx @@ -0,0 +1,156 @@ +"use client"; + +import { startTransition } from "react"; +import { Button, Card, Group, Stack, Switch, Text } from "@mantine/core"; +import { IconArrowRight } from "@tabler/icons-react"; + +import { clientApi } from "@homarr/api/client"; +import { revalidatePathActionAsync } from "@homarr/common/client"; +import { useZodForm } from "@homarr/form"; +import type { CheckboxProps } from "@homarr/form/types"; +import { defaultServerSettings } from "@homarr/server-settings"; +import type { TranslationObject } from "@homarr/translation"; +import { useI18n, useScopedI18n } from "@homarr/translation/client"; +import type { z } from "@homarr/validation"; +import { validation } from "@homarr/validation"; + +export const InitSettings = () => { + const tSection = useScopedI18n("management.page.settings.section"); + const t = useI18n(); + const { mutateAsync } = clientApi.serverSettings.initSettings.useMutation(); + const form = useZodForm(validation.settings.init, { initialValues: defaultServerSettings }); + + form.watch("analytics.enableGeneral", ({ value }) => { + if (!value) { + startTransition(() => { + form.setFieldValue("analytics.enableWidgetData", false); + form.setFieldValue("analytics.enableIntegrationData", false); + form.setFieldValue("analytics.enableUserData", false); + }); + } + }); + + const handleSubmitAsync = async (values: z.infer) => { + await mutateAsync(values, { + async onSuccess() { + await revalidatePathActionAsync("/init"); + }, + }); + }; + + return ( +
+ + + + {tSection("analytics.title")} + + + + + + + + + + + + + + + {tSection("crawlingAndIndexing.title")} + + + + + + + + + + + + +
+ ); +}; + +interface AnalyticsRowProps { + kind: Exclude; + disabled?: boolean; +} + +const AnalyticsRow = ({ kind, ...props }: AnalyticsRowProps & CheckboxProps) => { + const tSection = useI18n("management.page.settings.section"); + + return ( + + ); +}; + +interface CrawlingRowProps { + kind: Exclude< + keyof TranslationObject["management"]["page"]["settings"]["section"]["crawlingAndIndexing"], + "title" | "warning" + >; +} + +const CrawlingRow = ({ kind, ...inputProps }: CrawlingRowProps & CheckboxProps) => { + const tSection = useI18n("management.page.settings.section"); + + return ( + + ); +}; + +const SettingRow = ({ + title, + text, + disabled, + ...inputProps +}: { title: string; text: string; disabled?: boolean } & CheckboxProps) => { + return ( + + + + {title} + + + {text} + + + + + + ); +}; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/start/init-start.tsx b/apps/nextjs/src/app/[locale]/init/_steps/start/init-start.tsx new file mode 100644 index 000000000..b5005f8b4 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_steps/start/init-start.tsx @@ -0,0 +1,32 @@ +import { Card, Stack, Text } from "@mantine/core"; +import { IconFileImport, IconPlayerPlay } from "@tabler/icons-react"; + +import { getMantineColor } from "@homarr/common"; +import { getScopedI18n } from "@homarr/translation/server"; + +import { InitStartButton } from "./next-button"; + +export const InitStart = async () => { + const tStart = await getScopedI18n("init.step.start"); + + return ( + + + {tStart("description")} + + } + > + {tStart("action.scratch")} + + } + > + {tStart("action.importOldmarr")} + + + + ); +}; diff --git a/apps/nextjs/src/app/[locale]/init/_steps/start/next-button.tsx b/apps/nextjs/src/app/[locale]/init/_steps/start/next-button.tsx new file mode 100644 index 000000000..00ecf6f7d --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_steps/start/next-button.tsx @@ -0,0 +1,28 @@ +"use client"; + +import type { PropsWithChildren, ReactNode } from "react"; +import { Button } from "@mantine/core"; + +import { clientApi } from "@homarr/api/client"; +import { revalidatePathActionAsync } from "@homarr/common/client"; +import type { OnboardingStep } from "@homarr/definitions"; + +interface InitStartButtonProps { + icon: ReactNode; + preferredStep: OnboardingStep | undefined; +} + +export const InitStartButton = ({ preferredStep, icon, children }: PropsWithChildren) => { + const { mutateAsync } = clientApi.onboard.nextStep.useMutation(); + + const handleClickAsync = async () => { + await mutateAsync({ preferredStep }); + await revalidatePathActionAsync("/init"); + }; + + return ( + + ); +}; diff --git a/apps/nextjs/src/app/[locale]/init/user/_init-user-form.tsx b/apps/nextjs/src/app/[locale]/init/_steps/user/init-user-form.tsx similarity index 77% rename from apps/nextjs/src/app/[locale]/init/user/_init-user-form.tsx rename to apps/nextjs/src/app/[locale]/init/_steps/user/init-user-form.tsx index e22e81e47..2dcfac8f1 100644 --- a/apps/nextjs/src/app/[locale]/init/user/_init-user-form.tsx +++ b/apps/nextjs/src/app/[locale]/init/_steps/user/init-user-form.tsx @@ -1,9 +1,9 @@ "use client"; -import { useRouter } from "next/navigation"; import { Button, PasswordInput, Stack, TextInput } from "@mantine/core"; import { clientApi } from "@homarr/api/client"; +import { revalidatePathActionAsync } from "@homarr/common/client"; import { useZodForm } from "@homarr/form"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { useScopedI18n } from "@homarr/translation/client"; @@ -12,9 +12,9 @@ import type { z } from "@homarr/validation"; import { validation } from "@homarr/validation"; export const InitUserForm = () => { - const router = useRouter(); const t = useScopedI18n("user"); - const { mutateAsync, error, isPending } = clientApi.user.initUser.useMutation(); + const tUser = useScopedI18n("init.step.user"); + const { mutateAsync, isPending } = clientApi.user.initUser.useMutation(); const form = useZodForm(validation.user.init, { initialValues: { username: "", @@ -25,17 +25,17 @@ export const InitUserForm = () => { const handleSubmitAsync = async (values: FormType) => { await mutateAsync(values, { - onSuccess: () => { + async onSuccess() { showSuccessNotification({ - title: "User created", - message: "You can now log in", + title: tUser("notification.success.title"), + message: tUser("notification.success.message"), }); - router.push("/auth/login"); + await revalidatePathActionAsync("/init"); }, - onError: () => { + onError: (error) => { showErrorNotification({ - title: "User creation failed", - message: error?.message ?? "Unknown error", + title: tUser("notification.error.title"), + message: error.message, }); }, }); diff --git a/apps/nextjs/src/app/[locale]/init/_steps/user/init-user.tsx b/apps/nextjs/src/app/[locale]/init/_steps/user/init-user.tsx new file mode 100644 index 000000000..0f52de3dc --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/_steps/user/init-user.tsx @@ -0,0 +1,11 @@ +import { Card } from "@mantine/core"; + +import { InitUserForm } from "./init-user-form"; + +export const InitUser = () => { + return ( + + + + ); +}; diff --git a/apps/nextjs/src/app/[locale]/init/page.tsx b/apps/nextjs/src/app/[locale]/init/page.tsx new file mode 100644 index 000000000..5684e5709 --- /dev/null +++ b/apps/nextjs/src/app/[locale]/init/page.tsx @@ -0,0 +1,56 @@ +import type { JSX } from "react"; +import { Box, Center, Stack, Text, Title } from "@mantine/core"; + +import { api } from "@homarr/api/server"; +import type { MaybePromise } from "@homarr/common/types"; +import type { OnboardingStep } from "@homarr/definitions"; +import { getScopedI18n } from "@homarr/translation/server"; + +import { CurrentColorSchemeCombobox } from "~/components/color-scheme/current-color-scheme-combobox"; +import { CurrentLanguageCombobox } from "~/components/language/current-language-combobox"; +import { HomarrLogoWithTitle } from "~/components/layout/logo/homarr-logo"; +import { BackToStart } from "./_steps/back"; +import { InitFinish } from "./_steps/finish/init-finish"; +import { InitGroup } from "./_steps/group/init-group"; +import { InitImport } from "./_steps/import/init-import"; +import { InitSettings } from "./_steps/settings/init-settings"; +import { InitStart } from "./_steps/start/init-start"; +import { InitUser } from "./_steps/user/init-user"; + +const stepComponents: Record MaybePromise)> = { + start: InitStart, + import: InitImport, + user: InitUser, + group: InitGroup, + settings: InitSettings, + finish: InitFinish, +}; + +export default async function InitPage() { + const t = await getScopedI18n("init.step"); + const currentStep = await api.onboard.currentStep(); + + const CurrentComponent = stepComponents[currentStep.current]; + + return ( + +
+ + + + + {t(`${currentStep.current}.title`)} + + + {t(`${currentStep.current}.subtitle`)} + + + + + {CurrentComponent && } + {currentStep.previous === "start" && } + +
+
+ ); +} diff --git a/apps/nextjs/src/app/[locale]/init/user/page.tsx b/apps/nextjs/src/app/[locale]/init/user/page.tsx deleted file mode 100644 index 95fdaa145..000000000 --- a/apps/nextjs/src/app/[locale]/init/user/page.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { notFound } from "next/navigation"; -import { Card, Center, Stack, Text, Title } from "@mantine/core"; - -import { db } from "@homarr/db"; -import { getScopedI18n } from "@homarr/translation/server"; - -import { HomarrLogoWithTitle } from "~/components/layout/logo/homarr-logo"; -import { InitUserForm } from "./_init-user-form"; - -export default async function InitUser() { - const firstUser = await db.query.users.findFirst({ - columns: { - id: true, - }, - }); - - if (firstUser) { - notFound(); - } - - const t = await getScopedI18n("user.page.init"); - - return ( -
- - - - - {t("title")} - - - {t("subtitle")} - - - - - - -
- ); -} diff --git a/apps/nextjs/src/app/[locale]/layout.tsx b/apps/nextjs/src/app/[locale]/layout.tsx index afa2e413e..8f145ee3c 100644 --- a/apps/nextjs/src/app/[locale]/layout.tsx +++ b/apps/nextjs/src/app/[locale]/layout.tsx @@ -9,11 +9,12 @@ import "~/styles/scroll-area.scss"; import { notFound } from "next/navigation"; import { NextIntlClientProvider } from "next-intl"; -import { env } from "@homarr/auth/env.mjs"; +import { env } from "@homarr/auth/env"; import { auth } from "@homarr/auth/next"; import { ModalProvider } from "@homarr/modals"; import { Notifications } from "@homarr/notifications"; import { SpotlightProvider } from "@homarr/spotlight"; +import type { SupportedLanguage } from "@homarr/translation"; import { isLocaleRTL, isLocaleSupported } from "@homarr/translation"; import { getI18nMessages } from "@homarr/translation/server"; @@ -63,14 +64,17 @@ export const viewport: Viewport = { ], }; -export default async function Layout(props: { children: React.ReactNode; params: { locale: string } }) { - if (!isLocaleSupported(props.params.locale)) { +export default async function Layout(props: { + children: React.ReactNode; + params: Promise<{ locale: SupportedLanguage }>; +}) { + if (!isLocaleSupported((await props.params).locale)) { notFound(); } const session = await auth(); const colorScheme = await getCurrentColorSchemeAsync(); - const direction = isLocaleRTL(props.params.locale) ? "rtl" : "ltr"; + const direction = isLocaleRTL((await props.params).locale) ? "rtl" : "ltr"; const i18nMessages = await getI18nMessages(); const StackedProvider = composeWrappers([ @@ -89,7 +93,7 @@ export default async function Layout(props: { children: React.ReactNode; params: return ( // Instead of ColorSchemScript we use data-mantine-color-scheme to prevent flickering { - const arrayInChunks = splitToNChunks(icons, countIconGroups); const gridSpan = 12 / countIconGroups; return ( diff --git a/apps/nextjs/src/app/[locale]/manage/about/page.tsx b/apps/nextjs/src/app/[locale]/manage/about/page.tsx index f500f604a..024267be2 100644 --- a/apps/nextjs/src/app/[locale]/manage/about/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/about/page.tsx @@ -37,16 +37,16 @@ export async function generateMetadata() { }; } -const getHost = () => { +const getHostAsync = async () => { if (process.env.HOSTNAME) { return `${process.env.HOSTNAME}:3000`; } - return headers().get("host"); + return (await headers()).get("host"); }; export default async function AboutPage() { - const baseServerUrl = `http://${getHost()}`; + const baseServerUrl = `http://${await getHostAsync()}`; const t = await getScopedI18n("management.page.about"); const attributes = await getPackageAttributesAsync(); const githubContributors = (await fetch(`${baseServerUrl}/api/about/contributors/github`).then((res) => diff --git a/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/page.tsx b/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/page.tsx index f5fbc5d6f..a931b2ece 100644 --- a/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/apps/edit/[id]/page.tsx @@ -9,10 +9,11 @@ import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; import { AppEditForm } from "./_app-edit-form"; interface AppEditPageProps { - params: { id: string }; + params: Promise<{ id: string }>; } -export default async function AppEditPage({ params }: AppEditPageProps) { +export default async function AppEditPage(props: AppEditPageProps) { + const params = await props.params; const session = await auth(); if (!session?.user.permissions.includes("app-modify-all")) { diff --git a/apps/nextjs/src/app/[locale]/manage/apps/page.tsx b/apps/nextjs/src/app/[locale]/manage/apps/page.tsx index 8dd13774b..5193166f3 100644 --- a/apps/nextjs/src/app/[locale]/manage/apps/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/apps/page.tsx @@ -6,8 +6,10 @@ import { IconBox, IconPencil } from "@tabler/icons-react"; import type { RouterOutputs } from "@homarr/api"; import { api } from "@homarr/api/server"; import { auth } from "@homarr/auth/next"; -import { parseAppHrefWithVariablesServer } from "@homarr/common/server"; +import type { inferSearchParamsFromSchema } from "@homarr/common/types"; import { getI18n, getScopedI18n } from "@homarr/translation/server"; +import { SearchInput, TablePagination } from "@homarr/ui"; +import { z } from "@homarr/validation"; import { ManageContainer } from "~/components/manage/manage-container"; import { MobileAffixButton } from "~/components/manage/mobile-affix-button"; @@ -15,22 +17,35 @@ import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; import { NoResults } from "~/components/no-results"; import { AppDeleteButton } from "./_app-delete-button"; -export default async function AppsPage() { +const searchParamsSchema = z.object({ + search: z.string().optional(), + pageSize: z.string().regex(/\d+/).transform(Number).catch(10), + page: z.string().regex(/\d+/).transform(Number).catch(1), +}); + +interface AppsPageProps { + searchParams: Promise>; +} + +export default async function AppsPage(props: AppsPageProps) { const session = await auth(); if (!session) { redirect("/auth/login"); } - const apps = await api.app.all(); + const searchParams = searchParamsSchema.parse(await props.searchParams); + + const { items: apps, totalCount } = await api.app.getPaginated(searchParams); const t = await getScopedI18n("app"); return ( + {t("page.list.title")} - {t("page.list.title")} + {session.user.permissions.includes("app-create") && ( {t("page.create.title")} @@ -45,6 +60,10 @@ export default async function AppsPage() { ))} )} + + + +
); @@ -59,7 +78,7 @@ const AppCard = async ({ app }: AppCardProps) => { const session = await auth(); return ( - + { )} {app.href && ( - - {parseAppHrefWithVariablesServer(app.href)} + + {app.href} )} diff --git a/apps/nextjs/src/app/[locale]/manage/boards/_components/board-card-menu-dropdown.tsx b/apps/nextjs/src/app/[locale]/manage/boards/_components/board-card-menu-dropdown.tsx index dd7794db8..68ecf3a57 100644 --- a/apps/nextjs/src/app/[locale]/manage/boards/_components/board-card-menu-dropdown.tsx +++ b/apps/nextjs/src/app/[locale]/manage/boards/_components/board-card-menu-dropdown.tsx @@ -3,12 +3,14 @@ import { useCallback } from "react"; import Link from "next/link"; import { Menu } from "@mantine/core"; -import { IconHome, IconSettings, IconTrash } from "@tabler/icons-react"; +import { IconCopy, IconDeviceMobile, IconHome, IconSettings, IconTrash } from "@tabler/icons-react"; import type { RouterOutputs } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; +import { useSession } from "@homarr/auth/client"; import { revalidatePathActionAsync } from "@homarr/common/client"; -import { useConfirmModal } from "@homarr/modals"; +import { useConfirmModal, useModalAction } from "@homarr/modals"; +import { DuplicateBoardModal } from "@homarr/modals-collection"; import { useScopedI18n } from "@homarr/translation/client"; import { useBoardPermissions } from "~/components/board/permissions/client"; @@ -30,8 +32,10 @@ export const BoardCardMenuDropdown = ({ board }: BoardCardMenuDropdownProps) => const tCommon = useScopedI18n("common"); const { hasFullAccess, hasChangeAccess } = useBoardPermissions(board); + const { data: session } = useSession(); const { openConfirmModal } = useConfirmModal(); + const { openModal: openDuplicateModal } = useModalAction(DuplicateBoardModal); const setHomeBoardMutation = clientApi.board.setHomeBoard.useMutation({ onSettled: async () => { @@ -39,6 +43,12 @@ export const BoardCardMenuDropdown = ({ board }: BoardCardMenuDropdownProps) => await revalidatePathActionAsync("/"); }, }); + const setMobileHomeBoardMutation = clientApi.board.setMobileHomeBoard.useMutation({ + onSettled: async () => { + // Revalidate all as it's part of the user settings, /boards page and board manage page + await revalidatePathActionAsync("/"); + }, + }); const deleteBoardMutation = clientApi.board.deleteBoard.useMutation({ onSettled: async () => { await revalidatePathActionAsync("/manage/boards"); @@ -64,11 +74,35 @@ export const BoardCardMenuDropdown = ({ board }: BoardCardMenuDropdownProps) => await setHomeBoardMutation.mutateAsync({ id: board.id }); }, [board.id, setHomeBoardMutation]); + const handleSetMobileHomeBoard = useCallback(async () => { + await setMobileHomeBoardMutation.mutateAsync({ id: board.id }); + }, [board.id, setMobileHomeBoardMutation]); + + const handleDuplicateBoard = useCallback(() => { + openDuplicateModal({ + board: { + id: board.id, + name: board.name, + }, + onSuccess: async () => { + await revalidatePathActionAsync("/manage/boards"); + }, + }); + }, [board.id, board.name, openDuplicateModal]); + return ( }> {t("setHomeBoard.label")} + }> + {t("setMobileHomeBoard.label")} + + {session?.user.permissions.includes("board-create") && ( + }> + {t("duplicate.label")} + + )} {hasChangeAccess && ( <> diff --git a/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx b/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx index 0aa295481..849db72e7 100644 --- a/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx +++ b/apps/nextjs/src/app/[locale]/manage/boards/_components/create-board-button.tsx @@ -1,12 +1,11 @@ "use client"; -import { Affix, Button, Group, Menu } from "@mantine/core"; +import { Affix, Button, Menu } from "@mantine/core"; import { IconCategoryPlus, IconChevronDown, IconFileImport } from "@tabler/icons-react"; import { useModalAction } from "@homarr/modals"; import { AddBoardModal, ImportBoardModal } from "@homarr/modals-collection"; import { useI18n } from "@homarr/translation/client"; -import { BetaBadge } from "@homarr/ui"; export const CreateBoardButton = () => { const t = useI18n(); @@ -26,10 +25,7 @@ export const CreateBoardButton = () => { }> - - {t("board.action.oldImport.label")} - - + {t("board.action.oldImport.label")} diff --git a/apps/nextjs/src/app/[locale]/manage/boards/page.tsx b/apps/nextjs/src/app/[locale]/manage/boards/page.tsx index 58b234d24..4974b6a86 100644 --- a/apps/nextjs/src/app/[locale]/manage/boards/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/boards/page.tsx @@ -15,7 +15,7 @@ import { Title, Tooltip, } from "@mantine/core"; -import { IconDotsVertical, IconHomeFilled, IconLock, IconWorld } from "@tabler/icons-react"; +import { IconDeviceMobile, IconDotsVertical, IconHomeFilled, IconLock, IconWorld } from "@tabler/icons-react"; import type { RouterOutputs } from "@homarr/api"; import { api } from "@homarr/api/server"; @@ -67,7 +67,7 @@ const BoardCard = async ({ board }: BoardCardProps) => { const VisibilityIcon = board.isPublic ? IconWorld : IconLock; return ( - + @@ -88,6 +88,14 @@ const BoardCard = async ({ board }: BoardCardProps) => { )} + {board.isMobileHome && ( + + }> + {t("action.setMobileHomeBoard.badge.label")} + + + )} + {board.creator && ( diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx index 6962390f4..06c4baff3 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-card.tsx @@ -1,13 +1,14 @@ "use client"; import { useState } from "react"; -import { ActionIcon, Avatar, Button, Card, Collapse, Group, Kbd, Stack, Text } from "@mantine/core"; +import { ActionIcon, Avatar, Badge, Button, Card, Collapse, Group, Kbd, Stack, Text, Tooltip } from "@mantine/core"; import { useDisclosure } from "@mantine/hooks"; import { IconEye, IconEyeOff } from "@tabler/icons-react"; import dayjs from "dayjs"; import relativeTime from "dayjs/plugin/relativeTime"; import type { RouterOutputs } from "@homarr/api"; +import type { IntegrationSecretKind } from "@homarr/definitions"; import { integrationSecretKindObject } from "@homarr/definitions"; import { useI18n } from "@homarr/translation/client"; @@ -16,7 +17,9 @@ import { integrationSecretIcons } from "./integration-secret-icons"; dayjs.extend(relativeTime); interface SecretCardProps { - secret: RouterOutputs["integration"]["byId"]["secrets"][number]; + secret: + | RouterOutputs["integration"]["byId"]["secrets"][number] + | { kind: IntegrationSecretKind; value: null; updatedAt: null }; children: React.ReactNode; onCancel: () => Promise; } @@ -30,7 +33,7 @@ export const SecretCard = ({ secret, children, onCancel }: SecretCardProps) => { const KindIcon = integrationSecretIcons[secret.kind]; return ( - + @@ -41,11 +44,19 @@ export const SecretCard = ({ secret, children, onCancel }: SecretCardProps) => { {publicSecretDisplayOpened ? {secret.value} : null} - - {t("integration.secrets.lastUpdated", { - date: dayjs().to(dayjs(secret.updatedAt)), - })} - + {secret.updatedAt ? ( + + {t("integration.secrets.lastUpdated", { + date: dayjs().to(dayjs(secret.updatedAt)), + })} + + ) : ( + + + {t("integration.secrets.notSet.label")} + + + )} {isPublic ? ( diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-icons.ts b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-icons.ts index b2593aaf7..16266f889 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-icons.ts +++ b/apps/nextjs/src/app/[locale]/manage/integrations/_components/secrets/integration-secret-icons.ts @@ -1,4 +1,4 @@ -import { IconKey, IconPassword, IconUser } from "@tabler/icons-react"; +import { IconGrid3x3, IconKey, IconPassword, IconServer, IconUser } from "@tabler/icons-react"; import type { IntegrationSecretKind } from "@homarr/definitions"; import type { TablerIcon } from "@homarr/ui"; @@ -7,4 +7,6 @@ export const integrationSecretIcons = { username: IconUser, apiKey: IconKey, password: IconPassword, + realm: IconServer, + tokenId: IconGrid3x3, } satisfies Record; diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx index 60707e35a..867689b7e 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/_integration-edit-form.tsx @@ -98,8 +98,7 @@ export const EditIntegrationForm = ({ integration }: EditIntegrationForm) => { {secretsKinds.map((kind, index) => ( new Promise((resolve) => { // When nothing changed, just close the secret card diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/page.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/page.tsx index ede3d7a71..8cd8bf01b 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/edit/[id]/page.tsx @@ -11,10 +11,11 @@ import { IntegrationAccessSettings } from "../../_components/integration-access- import { EditIntegrationForm } from "./_integration-edit-form"; interface EditIntegrationPageProps { - params: { id: string }; + params: Promise<{ id: string }>; } -export default async function EditIntegrationPage({ params }: EditIntegrationPageProps) { +export default async function EditIntegrationPage(props: EditIntegrationPageProps) { + const params = await props.params; const editT = await getScopedI18n("integration.page.edit"); const t = await getI18n(); const integration = await api.integration.byId({ id: params.id }).catch(catchTrpcNotFound); diff --git a/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx b/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx index 791be2938..a223e3bfc 100644 --- a/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx +++ b/apps/nextjs/src/app/[locale]/manage/integrations/new/_integration-new-form.tsx @@ -3,13 +3,13 @@ import { useCallback } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; -import { Alert, Button, Fieldset, Group, SegmentedControl, Stack, Text, TextInput } from "@mantine/core"; +import { Alert, Button, Checkbox, Fieldset, Group, SegmentedControl, Stack, Text, TextInput } from "@mantine/core"; import { IconInfoCircle } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { revalidatePathActionAsync } from "@homarr/common/client"; import type { IntegrationKind, IntegrationSecretKind } from "@homarr/definitions"; -import { getAllSecretKindOptions, getIntegrationName } from "@homarr/definitions"; +import { getAllSecretKindOptions, getIntegrationName, integrationDefs } from "@homarr/definitions"; import type { UseFormReturnType } from "@homarr/form"; import { useZodForm } from "@homarr/form"; import { convertIntegrationTestConnectionError } from "@homarr/integrations/client"; @@ -38,6 +38,7 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) => kind, value: "", })), + attemptSearchEngineCreation: true, }, }); const { mutateAsync, isPending } = clientApi.integration.create.useMutation(); @@ -78,6 +79,8 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) => ); }; + const supportsSearchEngine = integrationDefs[searchParams.kind].category.flat().includes("search"); + return (
void handleSubmitAsync(value))}> @@ -104,6 +107,16 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) => + {supportsSearchEngine && ( + + )} + + )} + + ); +}; + +interface UploadMediaProps { + children: (props: { onClick: () => void; loading: boolean }) => JSX.Element; + onSettled?: () => MaybePromise; + onSuccess?: (media: { id: string; url: string }) => MaybePromise; +} + +export const UploadMedia = ({ children, onSettled, onSuccess }: UploadMediaProps) => { const t = useI18n(); const { mutateAsync, isPending } = clientApi.media.uploadMedia.useMutation(); @@ -18,10 +43,14 @@ export const UploadMedia = () => { const formData = new FormData(); formData.append("file", file); await mutateAsync(formData, { - onSuccess() { + async onSuccess(mediaId) { showSuccessNotification({ message: t("media.action.upload.notification.success.message"), }); + await onSuccess?.({ + id: mediaId, + url: `/api/user-medias/${mediaId}`, + }); }, onError() { showErrorNotification({ @@ -29,18 +58,14 @@ export const UploadMedia = () => { }); }, async onSettled() { - await revalidatePathActionAsync("/manage/medias"); + await onSettled?.(); }, }); }; return ( - {({ onClick }) => ( - - )} + {({ onClick }) => children({ onClick, loading: isPending })} ); }; diff --git a/apps/nextjs/src/app/[locale]/manage/medias/page.tsx b/apps/nextjs/src/app/[locale]/manage/medias/page.tsx index 5052194c9..102e54cd8 100644 --- a/apps/nextjs/src/app/[locale]/manage/medias/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/medias/page.tsx @@ -7,6 +7,7 @@ import type { RouterOutputs } from "@homarr/api"; import { api } from "@homarr/api/server"; import { auth } from "@homarr/auth/next"; import { humanFileSize } from "@homarr/common"; +import type { inferSearchParamsFromSchema } from "@homarr/common/types"; import { getI18n } from "@homarr/translation/server"; import { SearchInput, TablePagination, UserAvatar } from "@homarr/ui"; import { z } from "@homarr/validation"; @@ -16,7 +17,7 @@ import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; import { CopyMedia } from "./_actions/copy-media"; import { DeleteMedia } from "./_actions/delete-media"; import { IncludeFromAllUsersSwitch } from "./_actions/show-all"; -import { UploadMedia } from "./_actions/upload-media"; +import { UploadMediaButton } from "./_actions/upload-media"; const searchParamsSchema = z.object({ search: z.string().optional(), @@ -29,12 +30,8 @@ const searchParamsSchema = z.object({ page: z.string().regex(/\d+/).transform(Number).catch(1), }); -type SearchParamsSchemaInputFromSchema> = Partial<{ - [K in keyof TSchema]: Exclude extends unknown[] ? string[] : string; -}>; - interface MediaListPageProps { - searchParams: SearchParamsSchemaInputFromSchema>; + searchParams: Promise>; } export default async function GroupsListPage(props: MediaListPageProps) { @@ -45,7 +42,7 @@ export default async function GroupsListPage(props: MediaListPageProps) { } const t = await getI18n(); - const searchParams = searchParamsSchema.parse(props.searchParams); + const searchParams = searchParamsSchema.parse(await props.searchParams); const { items: medias, totalCount } = await api.media.getPaginated(searchParams); return ( @@ -61,7 +58,7 @@ export default async function GroupsListPage(props: MediaListPageProps) { )} - {session.user.permissions.includes("media-upload") && } + {session.user.permissions.includes("media-upload") && } diff --git a/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/page.tsx b/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/page.tsx index 39dfd8f63..9d618ad82 100644 --- a/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/search-engines/edit/[id]/page.tsx @@ -10,10 +10,11 @@ import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb"; import { SearchEngineEditForm } from "./_search-engine-edit-form"; interface SearchEngineEditPageProps { - params: { id: string }; + params: Promise<{ id: string }>; } -export default async function SearchEngineEditPage({ params }: SearchEngineEditPageProps) { +export default async function SearchEngineEditPage(props: SearchEngineEditPageProps) { + const params = await props.params; const session = await auth(); if (!session?.user.permissions.includes("search-engine-modify-all")) { diff --git a/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx b/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx index 5d56fe17c..8caeefbe7 100644 --- a/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx +++ b/apps/nextjs/src/app/[locale]/manage/search-engines/page.tsx @@ -6,6 +6,7 @@ import { IconPencil, IconSearch } from "@tabler/icons-react"; import type { RouterOutputs } from "@homarr/api"; import { api } from "@homarr/api/server"; import { auth } from "@homarr/auth/next"; +import type { inferSearchParamsFromSchema } from "@homarr/common/types"; import { getI18n, getScopedI18n } from "@homarr/translation/server"; import { SearchInput, TablePagination } from "@homarr/ui"; import { z } from "@homarr/validation"; @@ -22,12 +23,8 @@ const searchParamsSchema = z.object({ page: z.string().regex(/\d+/).transform(Number).catch(1), }); -type SearchParamsSchemaInputFromSchema> = Partial<{ - [K in keyof TSchema]: Exclude extends unknown[] ? string[] : string; -}>; - interface SearchEnginesPageProps { - searchParams: SearchParamsSchemaInputFromSchema>; + searchParams: Promise>; } export default async function SearchEnginesPage(props: SearchEnginesPageProps) { @@ -37,7 +34,7 @@ export default async function SearchEnginesPage(props: SearchEnginesPageProps) { redirect("/auth/login"); } - const searchParams = searchParamsSchema.parse(props.searchParams); + const searchParams = searchParamsSchema.parse(await props.searchParams); const { items: searchEngines, totalCount } = await api.searchEngine.getPaginated(searchParams); const tEngine = await getScopedI18n("search.engine"); @@ -81,7 +78,7 @@ const SearchEngineCard = async ({ searchEngine }: SearchEngineCardProps) => { const session = await auth(); return ( - + + ({ + value: board.id, + label: board.name, + image: board.logoImageUrl, + }))} + SelectOption={({ label, image }: { value: string; label: string; image: string | null }) => ( + + {/* eslint-disable-next-line @next/next/no-img-element */} + {image ? {label} : } + + {label} + + + )} + {...form.getInputProps("mobileHomeBoardId")} + /> )} diff --git a/apps/nextjs/src/app/[locale]/manage/settings/_components/search-settings-form.tsx b/apps/nextjs/src/app/[locale]/manage/settings/_components/search-settings-form.tsx new file mode 100644 index 000000000..a39cab70d --- /dev/null +++ b/apps/nextjs/src/app/[locale]/manage/settings/_components/search-settings-form.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { Select } from "@mantine/core"; + +import { clientApi } from "@homarr/api/client"; +import type { ServerSettings } from "@homarr/server-settings"; +import { useScopedI18n } from "@homarr/translation/client"; + +import { CommonSettingsForm } from "./common-form"; + +export const SearchSettingsForm = ({ defaultValues }: { defaultValues: ServerSettings["search"] }) => { + const tSearch = useScopedI18n("management.page.settings.section.search"); + const [selectableSearchEngines] = clientApi.searchEngine.getSelectable.useSuspenseQuery({ withIntegrations: false }); + + return ( + + {(form) => ( + <> + + + + + + + + ); +}; + +type FormType = z.infer; diff --git a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-home-board.tsx b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-home-board.tsx index b6fe54770..1666e15b2 100644 --- a/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-home-board.tsx +++ b/apps/nextjs/src/app/[locale]/manage/users/[userId]/general/_components/_change-home-board.tsx @@ -18,13 +18,14 @@ interface ChangeHomeBoardFormProps { export const ChangeHomeBoardForm = ({ user, boardsData }: ChangeHomeBoardFormProps) => { const t = useI18n(); - const { mutate, isPending } = clientApi.user.changeHomeBoardId.useMutation({ + const { mutate, isPending } = clientApi.user.changeHomeBoards.useMutation({ async onSettled() { await revalidatePathActionAsync(`/manage/users/${user.id}`); }, onSuccess(_, variables) { form.setInitialValues({ homeBoardId: variables.homeBoardId, + mobileHomeBoardId: variables.mobileHomeBoardId, }); showSuccessNotification({ message: t("user.action.changeHomeBoard.notification.success.message"), @@ -36,9 +37,10 @@ export const ChangeHomeBoardForm = ({ user, boardsData }: ChangeHomeBoardFormPro }); }, }); - const form = useZodForm(validation.user.changeHomeBoard, { + const form = useZodForm(validation.user.changeHomeBoards, { initialValues: { homeBoardId: user.homeBoardId ?? "", + mobileHomeBoardId: user.mobileHomeBoardId ?? "", }, }); @@ -52,7 +54,18 @@ export const ChangeHomeBoardForm = ({ user, boardsData }: ChangeHomeBoardFormPro return (
- + setSearch(event.currentTarget.value)} + leftSection={} + placeholder={`${t("item.create.search")}...`} + data-autofocus + onKeyDown={(event) => { + // Add item if there is only one item in the list and user presses Enter + if (event.key === "Enter" && filteredItems.length === 1) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + handleAdd(filteredItems[0]!.kind); + } + }} + /> + + + {filteredItems.map((item) => ( + handleAdd(item.kind)} /> + ))} + + ); }).withOptions({ defaultTitle: (t) => t("item.create.title"), @@ -23,20 +69,18 @@ export const ItemSelectModal = createModal(({ actions }) => { }); const WidgetItem = ({ - kind, - definition, - closeModal, + item, + onSelect, }: { - kind: WidgetKind; - definition: WidgetDefinition; - closeModal: () => void; + item: { + kind: WidgetKind; + name: string; + description: string; + icon: TablerIcon; + }; + onSelect: () => void; }) => { const t = useI18n(); - const { createItem } = useItemActions(); - const handleAdd = (kind: WidgetKind) => { - createItem({ kind }); - closeModal(); - }; return ( @@ -44,25 +88,16 @@ const WidgetItem = ({
- +
- {t(`widget.${kind}.name`)} + {item.name} - {t(`widget.${kind}.description`)} + {item.description}
-
diff --git a/apps/nextjs/src/components/board/not-found.tsx b/apps/nextjs/src/components/board/not-found.tsx new file mode 100644 index 000000000..d597597de --- /dev/null +++ b/apps/nextjs/src/components/board/not-found.tsx @@ -0,0 +1,41 @@ +import { Anchor, AppShellMain, Center, Flex, Group, Image, Text, Title } from "@mantine/core"; + +import type { TablerIcon } from "@homarr/ui"; + +import { fullHeightWithoutHeaderAndFooter } from "~/constants"; +import { MainHeader } from "../layout/header"; +import { HomarrLogoWithTitle } from "../layout/logo/homarr-logo"; +import { ClientShell } from "../layout/shell"; + +export interface BoardNotFoundProps { + icon: TablerIcon | { src: string; alt: string }; + title: string; + description: string; + link: { + label: string; + href: string; + }; + notice: string; +} + +export const BoardNotFound = ({ icon: Icon, title, description, link, notice }: BoardNotFoundProps) => { + return ( + + } hasNavigation={false} /> + +
+ + + {"src" in Icon ? : } + + {title} + + {description} + {link.label} + {notice} + +
+
+
+ ); +}; diff --git a/apps/nextjs/src/components/board/sections/category/actions/remove-category.ts b/apps/nextjs/src/components/board/sections/category/actions/remove-category.ts new file mode 100644 index 000000000..19ec37601 --- /dev/null +++ b/apps/nextjs/src/components/board/sections/category/actions/remove-category.ts @@ -0,0 +1,111 @@ +import type { Board, CategorySection, DynamicSection, EmptySection, Section } from "~/app/[locale]/boards/_types"; + +export interface RemoveCategoryInput { + id: string; +} + +export const removeCategoryCallback = + (input: RemoveCategoryInput) => + (previous: Board): Board => { + const currentCategory = previous.sections.find( + (section): section is CategorySection => section.kind === "category" && section.id === input.id, + ); + if (!currentCategory) { + return previous; + } + + const emptySectionsAbove = previous.sections.filter( + (section): section is EmptySection => section.kind === "empty" && section.yOffset < currentCategory.yOffset, + ); + const aboveSection = emptySectionsAbove.sort((sectionA, sectionB) => sectionB.yOffset - sectionA.yOffset).at(0); + + const emptySectionsBelow = previous.sections.filter( + (section): section is EmptySection => section.kind === "empty" && section.yOffset > currentCategory.yOffset, + ); + const removedSection = emptySectionsBelow.sort((sectionA, sectionB) => sectionA.yOffset - sectionB.yOffset).at(0); + + if (!aboveSection || !removedSection) { + return previous; + } + + // Calculate the yOffset for the items in the currentCategory and removedWrapper to add them with the same offset to the aboveWrapper + const aboveYOffset = Math.max( + calculateYHeightWithOffsetForItems(aboveSection), + calculateYHeightWithOffsetForDynamicSections(previous.sections, aboveSection.id), + ); + const categoryYOffset = Math.max( + calculateYHeightWithOffsetForItems(currentCategory), + calculateYHeightWithOffsetForDynamicSections(previous.sections, currentCategory.id), + ); + + const previousCategoryItems = currentCategory.items.map((item) => ({ + ...item, + yOffset: item.yOffset + aboveYOffset, + })); + const previousBelowWrapperItems = removedSection.items.map((item) => ({ + ...item, + yOffset: item.yOffset + aboveYOffset + categoryYOffset, + })); + + return { + ...previous, + sections: [ + ...previous.sections.filter((section) => section.yOffset < aboveSection.yOffset && section.kind !== "dynamic"), + { + ...aboveSection, + items: [...aboveSection.items, ...previousCategoryItems, ...previousBelowWrapperItems], + }, + ...previous.sections + .filter( + (section): section is CategorySection | EmptySection => + section.yOffset > removedSection.yOffset && section.kind !== "dynamic", + ) + .map((section) => ({ + ...section, + position: section.yOffset - 2, + })), + ...previous.sections + .filter((section): section is DynamicSection => section.kind === "dynamic") + .map((dynamicSection) => { + // Move dynamic sections from removed section to above section with required yOffset + if (dynamicSection.parentSectionId === removedSection.id) { + return { + ...dynamicSection, + yOffset: dynamicSection.yOffset + aboveYOffset + categoryYOffset, + parentSectionId: aboveSection.id, + }; + } + + // Move dynamic sections from category to above section with required yOffset + if (dynamicSection.parentSectionId === currentCategory.id) { + return { + ...dynamicSection, + yOffset: dynamicSection.yOffset + aboveYOffset, + parentSectionId: aboveSection.id, + }; + } + + return dynamicSection; + }), + ], + }; + }; + +const calculateYHeightWithOffsetForDynamicSections = (sections: Section[], sectionId: string) => { + return sections.reduce((acc, section) => { + if (section.kind !== "dynamic" || section.parentSectionId !== sectionId) { + return acc; + } + + const yHeightWithOffset = section.yOffset + section.height; + if (yHeightWithOffset > acc) return yHeightWithOffset; + return acc; + }, 0); +}; + +const calculateYHeightWithOffsetForItems = (section: Section) => + section.items.reduce((acc, item) => { + const yHeightWithOffset = item.yOffset + item.height; + if (yHeightWithOffset > acc) return yHeightWithOffset; + return acc; + }, 0); diff --git a/apps/nextjs/src/components/board/sections/category/actions/test/remove-category.spec.ts b/apps/nextjs/src/components/board/sections/category/actions/test/remove-category.spec.ts new file mode 100644 index 000000000..89fd17a5a --- /dev/null +++ b/apps/nextjs/src/components/board/sections/category/actions/test/remove-category.spec.ts @@ -0,0 +1,125 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { describe, expect, test } from "vitest"; + +import type { DynamicSection, Item, Section } from "~/app/[locale]/boards/_types"; +import { removeCategoryCallback } from "../remove-category"; + +describe("Remove Category", () => { + test.each([ + [3, [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 5, 6], [3, 4], 2], + [5, [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4], [5, 6], 4], + [1, [0, 1, 2, 3, 4, 5, 6], [0, 3, 4, 5, 6], [1, 2], 0], + [3, [0, 3, 6, 7, 8], [0, 7, 8], [3, 6], 0], + ])( + "should remove category", + (removeId, initialYOffsets, expectedYOffsets, expectedRemovals, expectedLocationOfItems) => { + const sections = createSections(initialYOffsets); + + const input = removeId.toString(); + + const result = removeCategoryCallback({ id: input })({ sections } as never); + + expect(result.sections.map((section) => parseInt(section.id, 10))).toEqual(expectedYOffsets); + expectedRemovals.forEach((expectedRemoval) => { + expect(result.sections.find((section) => section.id === expectedRemoval.toString())).toBeUndefined(); + }); + const aboveSection = result.sections.find((section) => section.id === expectedLocationOfItems.toString()); + expect(aboveSection?.items.map((item) => parseInt(item.id, 10))).toEqual( + expect.arrayContaining(expectedRemovals), + ); + }, + ); + + test("should correctly move items to above empty section", () => { + const initialYOffsets = [0, 1, 2, 3, 4, 5, 6]; + const sections: Section[] = createSections(initialYOffsets); + const aboveSection = sections.find((section) => section.yOffset === 2)!; + aboveSection.items = [ + createItem({ id: "above-1" }), + createItem({ id: "above-2", yOffset: 3, xOffset: 2, height: 2 }), + ]; + const removedCategory = sections.find((section) => section.yOffset === 3)!; + removedCategory.items = [ + createItem({ id: "category-1" }), + createItem({ id: "category-2", yOffset: 2, xOffset: 4, width: 4 }), + ]; + const removedEmptySection = sections.find((section) => section.yOffset === 4)!; + removedEmptySection.items = [ + createItem({ id: "below-1", xOffset: 5 }), + createItem({ id: "below-2", yOffset: 1, xOffset: 1, height: 2 }), + ]; + sections.push( + createDynamicSection({ + id: "7", + parentSectionId: "3", + yOffset: 7, + height: 3, + items: [createItem({ id: "dynamic-1" })], + }), + ); + + const input = "3"; + + const result = removeCategoryCallback({ id: input })({ sections } as never); + + expect(result.sections.map((section) => parseInt(section.id, 10))).toEqual([0, 1, 2, 5, 6, 7]); + const aboveSectionResult = result.sections.find((section) => section.id === "2")!; + expect(aboveSectionResult.items).toEqual( + expect.arrayContaining([ + createItem({ id: "above-1" }), + createItem({ id: "above-2", yOffset: 3, xOffset: 2, height: 2 }), + createItem({ id: "category-1", yOffset: 5 }), + createItem({ id: "category-2", yOffset: 7, xOffset: 4, width: 4 }), + createItem({ id: "below-1", yOffset: 15, xOffset: 5 }), + createItem({ id: "below-2", yOffset: 16, xOffset: 1, height: 2 }), + ]), + ); + const dynamicSection = result.sections.find((section): section is DynamicSection => section.id === "7")!; + expect(dynamicSection.yOffset).toBe(12); + expect(dynamicSection.parentSectionId).toBe("2"); + }); +}); + +const createItem = (item: Partial<{ id: string; width: number; height: number; yOffset: number; xOffset: number }>) => { + return { + id: item.id ?? "0", + kind: "app", + options: {}, + advancedOptions: { + customCssClasses: [], + }, + height: item.height ?? 1, + width: item.width ?? 1, + yOffset: item.yOffset ?? 0, + xOffset: item.xOffset ?? 0, + integrationIds: [], + } satisfies Item; +}; + +const createDynamicSection = ( + section: Partial< + Pick + >, +) => { + return { + id: section.id ?? "0", + kind: "dynamic", + height: section.height ?? 1, + width: section.width ?? 1, + yOffset: section.yOffset ?? 0, + xOffset: section.xOffset ?? 0, + parentSectionId: section.parentSectionId ?? "0", + items: section.items ?? [], + } satisfies DynamicSection; +}; + +const createSections = (initialYOffsets: number[]) => { + return initialYOffsets.map((yOffset, index) => ({ + id: yOffset.toString(), + kind: index % 2 === 0 ? "empty" : "category", + name: "Category", + yOffset, + xOffset: 0, + items: [createItem({ id: yOffset.toString() })], + })) satisfies Section[]; +}; diff --git a/apps/nextjs/src/components/board/sections/category/category-actions.ts b/apps/nextjs/src/components/board/sections/category/category-actions.ts index 01e54a2b8..6bdcdc9ba 100644 --- a/apps/nextjs/src/components/board/sections/category/category-actions.ts +++ b/apps/nextjs/src/components/board/sections/category/category-actions.ts @@ -2,10 +2,12 @@ import { useCallback } from "react"; import { createId } from "@homarr/db/client"; -import type { CategorySection, EmptySection, Section } from "~/app/[locale]/boards/_types"; +import type { CategorySection, EmptySection } from "~/app/[locale]/boards/_types"; import { useUpdateBoard } from "~/app/[locale]/boards/(content)/_client"; import type { MoveCategoryInput } from "./actions/move-category"; import { moveCategoryCallback } from "./actions/move-category"; +import type { RemoveCategoryInput } from "./actions/remove-category"; +import { removeCategoryCallback } from "./actions/remove-category"; interface AddCategory { name: string; @@ -17,10 +19,6 @@ interface RenameCategory { name: string; } -interface RemoveCategory { - id: string; -} - export const useCategoryActions = () => { const { updateBoard } = useUpdateBoard(); @@ -132,57 +130,8 @@ export const useCategoryActions = () => { ); const removeCategory = useCallback( - ({ id: categoryId }: RemoveCategory) => { - updateBoard((previous) => { - const currentCategory = previous.sections.find( - (section): section is CategorySection => section.kind === "category" && section.id === categoryId, - ); - if (!currentCategory) return previous; - - const aboveWrapper = previous.sections.find( - (section): section is EmptySection => - section.kind === "empty" && section.yOffset === currentCategory.yOffset - 1, - ); - - const removedWrapper = previous.sections.find( - (section): section is EmptySection => - section.kind === "empty" && section.yOffset === currentCategory.yOffset + 1, - ); - - if (!aboveWrapper || !removedWrapper) return previous; - - // Calculate the yOffset for the items in the currentCategory and removedWrapper to add them with the same offset to the aboveWrapper - const aboveYOffset = calculateYHeightWithOffset(aboveWrapper); - const categoryYOffset = calculateYHeightWithOffset(currentCategory); - - const previousCategoryItems = currentCategory.items.map((item) => ({ - ...item, - yOffset: item.yOffset + aboveYOffset, - })); - const previousBelowWrapperItems = removedWrapper.items.map((item) => ({ - ...item, - yOffset: item.yOffset + aboveYOffset + categoryYOffset, - })); - - return { - ...previous, - sections: [ - ...previous.sections.filter((section) => section.yOffset < currentCategory.yOffset - 1), - { - ...aboveWrapper, - items: [...aboveWrapper.items, ...previousCategoryItems, ...previousBelowWrapperItems], - }, - ...previous.sections - .filter( - (section): section is CategorySection | EmptySection => section.yOffset >= currentCategory.yOffset + 2, - ) - .map((section) => ({ - ...section, - position: section.yOffset - 2, - })), - ], - }; - }); + (input: RemoveCategoryInput) => { + updateBoard(removeCategoryCallback(input)); }, [updateBoard], ); @@ -195,10 +144,3 @@ export const useCategoryActions = () => { removeCategory, }; }; - -const calculateYHeightWithOffset = (section: Section) => - section.items.reduce((acc, item) => { - const yHeightWithOffset = item.yOffset + item.height; - if (yHeightWithOffset > acc) return yHeightWithOffset; - return acc; - }, 0); diff --git a/apps/nextjs/src/components/board/sections/content.tsx b/apps/nextjs/src/components/board/sections/content.tsx index c9fe9feab..fd8b4b552 100644 --- a/apps/nextjs/src/components/board/sections/content.tsx +++ b/apps/nextjs/src/components/board/sections/content.tsx @@ -10,6 +10,12 @@ import { useSectionContext } from "./section-context"; export const SectionContent = () => { const { section, innerSections, refs } = useSectionContext(); const board = useRequiredBoard(); + + /** + * IMPORTANT: THE ORDER OF THE BELOW ITEMS HAS TO MATCH THE ORDER OF + * THE ITEMS RENDERED WITH GRIDSTACK, OTHERWISE THE ITEMS WILL BE MIXED UP + * @see https://github.com/homarr-labs/homarr/pull/1770 + */ const sortedItems = useMemo(() => { return [ ...section.items.map((item) => ({ ...item, type: "item" as const })), @@ -19,7 +25,7 @@ export const SectionContent = () => { return itemA.xOffset - itemB.xOffset; } - return itemA.yOffset - itemB.xOffset; + return itemA.yOffset - itemB.yOffset; }); }, [section.items, innerSections]); diff --git a/apps/nextjs/src/components/board/sections/item.module.css b/apps/nextjs/src/components/board/sections/item.module.css index af488c201..f679c62ca 100644 --- a/apps/nextjs/src/components/board/sections/item.module.css +++ b/apps/nextjs/src/components/board/sections/item.module.css @@ -7,6 +7,6 @@ --background-color: rgb(from var(--mantine-color-white) r g b / var(--opacity)); --border-color: rgb(from var(--mantine-color-gray-3) r g b / var(--opacity)); } - background-color: var(--background-color); - border-color: var(--border-color); + background-color: var(--background-color) !important; + border-color: var(--border-color) !important; } diff --git a/apps/nextjs/src/components/color-scheme/current-color-scheme-combobox.tsx b/apps/nextjs/src/components/color-scheme/current-color-scheme-combobox.tsx new file mode 100644 index 000000000..b3534c3aa --- /dev/null +++ b/apps/nextjs/src/components/color-scheme/current-color-scheme-combobox.tsx @@ -0,0 +1,49 @@ +"use client"; + +import { Group, Text, useMantineColorScheme } from "@mantine/core"; +import { IconMoon, IconSun } from "@tabler/icons-react"; + +import type { ColorScheme } from "@homarr/definitions"; +import { colorSchemes } from "@homarr/definitions"; +import { useScopedI18n } from "@homarr/translation/client"; +import { SelectWithCustomItems } from "@homarr/ui"; + +interface CurrentColorSchemeComboboxProps { + w?: string; +} + +export const CurrentColorSchemeCombobox = ({ w }: CurrentColorSchemeComboboxProps) => { + const tOptions = useScopedI18n("common.colorScheme.options"); + const { colorScheme, setColorScheme } = useMantineColorScheme(); + + return ( + setColorScheme((value as ColorScheme | null) ?? "light")} + data={colorSchemes.map((scheme) => ({ + value: scheme, + label: tOptions(scheme), + }))} + SelectOption={ColorSchemeCustomOption} + w={w} + /> + ); +}; + +const appearanceIcons = { + light: IconSun, + dark: IconMoon, +}; + +const ColorSchemeCustomOption = ({ value, label }: { value: ColorScheme; label: string }) => { + const Icon = appearanceIcons[value]; + + return ( + + + + {label} + + + ); +}; diff --git a/apps/nextjs/src/components/icons/picker/icon-picker.module.css b/apps/nextjs/src/components/icons/picker/icon-picker.module.css new file mode 100644 index 000000000..aa52af4b0 --- /dev/null +++ b/apps/nextjs/src/components/icons/picker/icon-picker.module.css @@ -0,0 +1,3 @@ +[data-combobox-selected="true"] .iconCard { + border-color: var(--mantine-primary-color-6); +} diff --git a/apps/nextjs/src/components/icons/picker/icon-picker.tsx b/apps/nextjs/src/components/icons/picker/icon-picker.tsx index 8a514f8a5..d0758a66e 100644 --- a/apps/nextjs/src/components/icons/picker/icon-picker.tsx +++ b/apps/nextjs/src/components/icons/picker/icon-picker.tsx @@ -1,10 +1,12 @@ import type { FocusEventHandler } from "react"; import { startTransition, useState } from "react"; import { + ActionIcon, Box, Card, Combobox, Flex, + Group, Image, Indicator, InputBase, @@ -16,10 +18,15 @@ import { useCombobox, } from "@mantine/core"; import { useDebouncedValue } from "@mantine/hooks"; +import { IconUpload } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; +import { useSession } from "@homarr/auth/client"; import { useScopedI18n } from "@homarr/translation/client"; +import { UploadMedia } from "~/app/[locale]/manage/medias/_actions/upload-media"; +import classes from "./icon-picker.module.css"; + interface IconPickerProps { initialValue?: string; onChange: (iconUrl: string) => void; @@ -32,6 +39,7 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I const [value, setValue] = useState(initialValue ?? ""); const [search, setSearch] = useState(initialValue ?? ""); const [previewUrl, setPreviewUrl] = useState(initialValue ?? null); + const { data: session } = useSession(); const tCommon = useScopedI18n("common"); @@ -49,34 +57,43 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I const totalOptions = data?.icons.reduce((acc, group) => acc + group.icons.length, 0) ?? 0; const groups = data?.icons.map((group) => { const options = group.icons.map((item) => ( - { - const value = item.url; - startTransition(() => { - setValue(value); - setPreviewUrl(value); - setSearch(value); - onChange(value); - combobox.closeDropdown(); - }); - }} + - - - - - - - - + { + const value = item.url; + startTransition(() => { + setValue(value); + setPreviewUrl(value); + setSearch(value); + onChange(value); + combobox.closeDropdown(); + }); + }} + > + + + + + + + + + )); return ( @@ -94,40 +111,61 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I return ( - } - leftSection={ - previewUrl ? ( - // eslint-disable-next-line @next/next/no-img-element - - ) : null - } - value={search} - onChange={(event) => { - combobox.openDropdown(); - combobox.updateSelectedOptionIndex(); - setSearch(event.currentTarget.value); - setValue(event.currentTarget.value); - setPreviewUrl(null); - onChange(event.currentTarget.value); - }} - onClick={() => combobox.openDropdown()} - onFocus={(event) => { - onFocus?.(event); - combobox.openDropdown(); - }} - onBlur={(event) => { - onBlur?.(event); - combobox.closeDropdown(); - setPreviewUrl(value); - setSearch(value || ""); - }} - rightSectionPointerEvents="none" - withAsterisk - error={error} - label={tCommon("iconPicker.label")} - placeholder={tCommon("iconPicker.header", { countIcons: data?.countIcons ?? 0 })} - /> + + } + leftSection={ + previewUrl ? ( + // eslint-disable-next-line @next/next/no-img-element + + ) : null + } + value={search} + onChange={(event) => { + combobox.openDropdown(); + combobox.updateSelectedOptionIndex(); + setSearch(event.currentTarget.value); + setValue(event.currentTarget.value); + setPreviewUrl(null); + onChange(event.currentTarget.value); + }} + onClick={() => combobox.openDropdown()} + onFocus={(event) => { + onFocus?.(event); + combobox.openDropdown(); + }} + onBlur={(event) => { + onBlur?.(event); + combobox.closeDropdown(); + setPreviewUrl(value); + setSearch(value || ""); + }} + rightSectionPointerEvents="none" + withAsterisk + error={error} + label={tCommon("iconPicker.label")} + placeholder={tCommon("iconPicker.header", { countIcons: data?.countIcons ?? 0 })} + /> + {session?.user.permissions.includes("media-upload") && ( + { + startTransition(() => { + setValue(url); + setPreviewUrl(url); + setSearch(url); + onChange(url); + }); + }} + > + {({ onClick, loading }) => ( + + + + )} + + )} + diff --git a/apps/nextjs/src/components/language/current-language-combobox.tsx b/apps/nextjs/src/components/language/current-language-combobox.tsx index cdb4709d6..e27f34c39 100644 --- a/apps/nextjs/src/components/language/current-language-combobox.tsx +++ b/apps/nextjs/src/components/language/current-language-combobox.tsx @@ -4,9 +4,13 @@ import { useChangeLocale, useCurrentLocale } from "@homarr/translation/client"; import { LanguageCombobox } from "./language-combobox"; -export const CurrentLanguageCombobox = () => { +interface CurrentLanguageComboboxProps { + width?: string; +} + +export const CurrentLanguageCombobox = ({ width }: CurrentLanguageComboboxProps) => { const currentLocale = useCurrentLocale(); const { changeLocale, isPending } = useChangeLocale(); - return ; + return ; }; diff --git a/apps/nextjs/src/components/language/language-combobox.tsx b/apps/nextjs/src/components/language/language-combobox.tsx index 91e968686..80ea2549b 100644 --- a/apps/nextjs/src/components/language/language-combobox.tsx +++ b/apps/nextjs/src/components/language/language-combobox.tsx @@ -9,14 +9,17 @@ import { localeConfigurations, supportedLanguages } from "@homarr/translation"; import classes from "./language-combobox.module.css"; +import "flag-icons/css/flag-icons.min.css"; + interface LanguageComboboxProps { label?: string; value: SupportedLanguage; onChange: (value: SupportedLanguage) => void; isPending?: boolean; + width?: string; } -export const LanguageCombobox = ({ label, value, onChange, isPending }: LanguageComboboxProps) => { +export const LanguageCombobox = ({ label, value, onChange, isPending, width }: LanguageComboboxProps) => { const combobox = useCombobox({ onDropdownClose: () => combobox.resetSelectedOption(), }); @@ -49,6 +52,7 @@ export const LanguageCombobox = ({ label, value, onChange, isPending }: Language rightSectionPointerEvents="none" onClick={handleOnClick} variant="filled" + w={width} > diff --git a/apps/nextjs/src/components/layout/header/user.tsx b/apps/nextjs/src/components/layout/header/user.tsx index 6ec355630..f4aabb767 100644 --- a/apps/nextjs/src/components/layout/header/user.tsx +++ b/apps/nextjs/src/components/layout/header/user.tsx @@ -1,13 +1,21 @@ -import { UnstyledButton } from "@mantine/core"; +import { Indicator, UnstyledButton } from "@mantine/core"; + +import { api } from "@homarr/api/server"; +import { auth } from "@homarr/auth/next"; import { CurrentUserAvatar } from "~/components/user-avatar"; import { UserAvatarMenu } from "~/components/user-avatar-menu"; -export const UserButton = () => { +export const UserButton = async () => { + const session = await auth(); + const isAdmin = session?.user.permissions.includes("admin"); + const data = isAdmin ? await api.updateChecker.getAvailableUpdates() : undefined; return ( - + - + + + ); diff --git a/apps/nextjs/src/components/user-avatar-menu.tsx b/apps/nextjs/src/components/user-avatar-menu.tsx index 503642482..d7a53f901 100644 --- a/apps/nextjs/src/components/user-avatar-menu.tsx +++ b/apps/nextjs/src/components/user-avatar-menu.tsx @@ -7,6 +7,7 @@ import { useRouter } from "next/navigation"; import { Center, Menu, Stack, Text, useMantineColorScheme } from "@mantine/core"; import { useHotkeys, useTimeout } from "@mantine/hooks"; import { + IconBellRinging, IconCheck, IconHome, IconLogin, @@ -17,20 +18,20 @@ import { IconTool, } from "@tabler/icons-react"; +import type { RouterOutputs } from "@homarr/api"; import { signOut, useSession } from "@homarr/auth/client"; import { createModal, useModalAction } from "@homarr/modals"; import { useScopedI18n } from "@homarr/translation/client"; -import "flag-icons/css/flag-icons.min.css"; - import { useAuthContext } from "~/app/[locale]/_client-providers/session"; import { CurrentLanguageCombobox } from "./language/current-language-combobox"; interface UserAvatarMenuProps { children: ReactNode; + availableUpdates?: RouterOutputs["updateChecker"]["getAvailableUpdates"]; } -export const UserAvatarMenu = ({ children }: UserAvatarMenuProps) => { +export const UserAvatarMenu = ({ children, availableUpdates }: UserAvatarMenuProps) => { const t = useScopedI18n("common.userAvatar.menu"); const { colorScheme, toggleColorScheme } = useMantineColorScheme(); useHotkeys([["mod+J", toggleColorScheme]]); @@ -64,6 +65,21 @@ export const UserAvatarMenu = ({ children }: UserAvatarMenuProps) => { // We use keepMounted so we can add event listeners to prevent navigating away without saving the board + {availableUpdates && availableUpdates.length > 0 && availableUpdates[0] && ( + <> + } + > + + {t("updateAvailable", { countUpdates: availableUpdates.length, tag: availableUpdates[0].tagName })} + + + + + )} }> {colorSchemeText} @@ -72,7 +88,7 @@ export const UserAvatarMenu = ({ children }: UserAvatarMenuProps) => { - + @@ -97,7 +113,7 @@ export const UserAvatarMenu = ({ children }: UserAvatarMenuProps) => { {t("logout")} ) : ( - router.push("/auth/login")} leftSection={}> + }> {t("login")} )} diff --git a/apps/nextjs/src/env.mjs b/apps/nextjs/src/env.mjs deleted file mode 100644 index bdef43eb0..000000000 --- a/apps/nextjs/src/env.mjs +++ /dev/null @@ -1,68 +0,0 @@ -import { createEnv } from "@t3-oss/env-nextjs"; -import { z } from "zod"; - -const isUsingDbUrl = Boolean(process.env.DB_URL); -const isUsingDbHost = Boolean(process.env.DB_HOST); -const isUsingDbCredentials = process.env.DB_DRIVER === "mysql2"; - -export const env = createEnv({ - shared: { - VERCEL_URL: z - .string() - .optional() - .transform((url) => (url ? `https://${url}` : undefined)), - PORT: z.coerce.number().default(3000), - NODE_ENV: z.enum(["development", "production", "test"]).default("development"), - }, - /** - * Specify your server-side environment variables schema here. This way you can ensure the app isn't - * built with invalid env vars. - */ - server: { - DB_DRIVER: z.enum(["better-sqlite3", "mysql2"]).default("better-sqlite3"), - // If the DB_HOST is set, the DB_URL is optional - DB_URL: isUsingDbHost ? z.string().optional() : z.string(), - DB_HOST: isUsingDbUrl ? z.string().optional() : z.string(), - DB_PORT: isUsingDbUrl - ? z.string().regex(/\d+/).transform(Number).optional() - : z - .string() - .regex(/\d+/) - .transform(Number) - .refine((number) => number >= 1) - .default("3306"), - DB_USER: isUsingDbCredentials ? z.string() : z.string().optional(), - DB_PASSWORD: isUsingDbCredentials ? z.string() : z.string().optional(), - DB_NAME: isUsingDbUrl ? z.string().optional() : z.string(), - // Comma separated list of docker hostnames that can be used to connect to query the docker endpoints (localhost:2375,host.docker.internal:2375, ...) - DOCKER_HOSTNAMES: z.string().optional(), - DOCKER_PORTS: z.number().optional(), - }, - /** - * Specify your client-side environment variables schema here. - * For them to be exposed to the client, prefix them with `NEXT_PUBLIC_`. - */ - client: { - // NEXT_PUBLIC_CLIENTVAR: z.string(), - }, - /** - * Destructure all variables from `process.env` to make sure they aren't tree-shaken away. - */ - runtimeEnv: { - VERCEL_URL: process.env.VERCEL_URL, - PORT: process.env.PORT, - DB_URL: process.env.DB_URL, - DB_HOST: process.env.DB_HOST, - DB_USER: process.env.DB_USER, - DB_PASSWORD: process.env.DB_PASSWORD, - DB_NAME: process.env.DB_NAME, - DB_PORT: process.env.DB_PORT, - DB_DRIVER: process.env.DB_DRIVER, - NODE_ENV: process.env.NODE_ENV, - DOCKER_HOSTNAMES: process.env.DOCKER_HOSTNAMES, - DOCKER_PORTS: process.env.DOCKER_PORTS, - // NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR, - }, - skipValidation: - Boolean(process.env.CI) || Boolean(process.env.SKIP_ENV_VALIDATION) || process.env.npm_lifecycle_event === "lint", -}); diff --git a/apps/nextjs/src/env.ts b/apps/nextjs/src/env.ts new file mode 100644 index 000000000..72d1c3837 --- /dev/null +++ b/apps/nextjs/src/env.ts @@ -0,0 +1,38 @@ +import { createEnv } from "@t3-oss/env-nextjs"; +import { z } from "zod"; + +import { shouldSkipEnvValidation } from "@homarr/common/env-validation"; + +export const env = createEnv({ + shared: { + PORT: z.coerce.number().default(3000), + NODE_ENV: z.enum(["development", "production", "test"]).default("development"), + }, + /** + * Specify your server-side environment variables schema here. This way you can ensure the app isn't + * built with invalid env vars. + */ + server: { + // Comma separated list of docker hostnames that can be used to connect to query the docker endpoints (localhost:2375,host.docker.internal:2375, ...) + DOCKER_HOSTNAMES: z.string().optional(), + DOCKER_PORTS: z.string().optional(), + }, + /** + * Specify your client-side environment variables schema here. + * For them to be exposed to the client, prefix them with `NEXT_PUBLIC_`. + */ + client: { + // NEXT_PUBLIC_CLIENTVAR: z.string(), + }, + /** + * Destructure all variables from `process.env` to make sure they aren't tree-shaken away. + */ + runtimeEnv: { + PORT: process.env.PORT, + NODE_ENV: process.env.NODE_ENV, + DOCKER_HOSTNAMES: process.env.DOCKER_HOSTNAMES, + DOCKER_PORTS: process.env.DOCKER_PORTS, + // NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR, + }, + skipValidation: shouldSkipEnvValidation(), +}); diff --git a/apps/nextjs/src/middleware.ts b/apps/nextjs/src/middleware.ts index f20def82b..8db4c4108 100644 --- a/apps/nextjs/src/middleware.ts +++ b/apps/nextjs/src/middleware.ts @@ -1,9 +1,10 @@ +import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; import { createTRPCClient, httpLink } from "@trpc/client"; import SuperJSON from "superjson"; import type { AppRouter } from "@homarr/api"; -import { createHeadersCallbackForSource } from "@homarr/api/client"; +import { createHeadersCallbackForSource } from "@homarr/api/shared"; import { createI18nMiddleware } from "@homarr/translation/middleware"; export async function middleware(request: NextRequest) { @@ -11,6 +12,15 @@ export async function middleware(request: NextRequest) { // In next 15 we will be able to use node apis and such the db directly const culture = await serverFetchApi.serverSettings.getCulture.query(); + // Redirect to onboarding if it's not finished yet + const pathname = request.nextUrl.pathname; + if (!pathname.endsWith("/init")) { + const currentOnboardingStep = await serverFetchApi.onboard.currentStep.query(); + if (currentOnboardingStep.current !== "finish") { + return NextResponse.redirect(new URL("/init", request.url)); + } + } + // We don't want to fallback to accept-language header so we clear it request.headers.set("accept-language", ""); const next = createI18nMiddleware(culture.defaultLocale); diff --git a/apps/nextjs/src/theme/color-scheme.ts b/apps/nextjs/src/theme/color-scheme.ts index 4f069a1ef..284b636b4 100644 --- a/apps/nextjs/src/theme/color-scheme.ts +++ b/apps/nextjs/src/theme/color-scheme.ts @@ -7,7 +7,7 @@ import type { ColorScheme } from "@homarr/definitions"; import { colorSchemeCookieKey } from "@homarr/definitions"; export const getCurrentColorSchemeAsync = cache(async () => { - const cookieValue = cookies().get(colorSchemeCookieKey)?.value; + const cookieValue = (await cookies()).get(colorSchemeCookieKey)?.value; if (cookieValue) { return cookieValue as ColorScheme; diff --git a/apps/nextjs/src/versions/package-reader.ts b/apps/nextjs/src/versions/package-reader.ts index 25976619e..a7da5b029 100644 --- a/apps/nextjs/src/versions/package-reader.ts +++ b/apps/nextjs/src/versions/package-reader.ts @@ -1,7 +1,7 @@ import fsPromises from "fs/promises"; import { glob } from "glob"; -import packageJson from "~/../package.json"; +import packageJson from "../../../../package.json"; const getPackageVersion = () => packageJson.version; const getDependenciesAsync = async (): Promise => { diff --git a/apps/tasks/package.json b/apps/tasks/package.json index 1097b0d62..a91ff776a 100644 --- a/apps/tasks/package.json +++ b/apps/tasks/package.json @@ -38,17 +38,17 @@ "dayjs": "^1.11.13", "dotenv": "^16.4.7", "superjson": "2.2.2", - "undici": "7.1.0" + "undici": "7.2.3" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "@types/node": "^22.10.2", - "dotenv-cli": "^7.4.4", - "eslint": "^9.16.0", + "@types/node": "^22.10.7", + "dotenv-cli": "^8.0.0", + "eslint": "^9.18.0", "prettier": "^3.4.2", "tsx": "4.19.2", - "typescript": "^5.7.2" + "typescript": "^5.7.3" } } diff --git a/apps/tasks/src/undici-log-agent-override.ts b/apps/tasks/src/undici-log-agent-override.ts index 8f0e49f00..f05432c02 100644 --- a/apps/tasks/src/undici-log-agent-override.ts +++ b/apps/tasks/src/undici-log-agent-override.ts @@ -1,35 +1,6 @@ -import type { Dispatcher } from "undici"; -import { Agent, setGlobalDispatcher } from "undici"; +import { setGlobalDispatcher } from "undici"; -import { logger } from "@homarr/log"; - -export class LoggingAgent extends Agent { - constructor(...props: ConstructorParameters) { - super(...props); - } - - dispatch(options: Dispatcher.DispatchOptions, handler: Dispatcher.DispatchHandler): boolean { - const url = new URL(`${options.origin as string}${options.path}`); - - // The below code should prevent sensitive data from being logged as - // some integrations use query parameters for auth - url.searchParams.forEach((value, key) => { - if (value === "") return; // Skip empty values - if (/^-?\d{1,12}$/.test(value)) return; // Skip small numbers - if (value === "true" || value === "false") return; // Skip boolean values - if (/^[a-zA-Z]{1,12}$/.test(value)) return; // Skip short strings - if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return; // Skip dates - if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value)) return; // Skip date times - - url.searchParams.set(key, "REDACTED"); - }); - - logger.info( - `Dispatching request ${url.toString().replaceAll("=&", "&")} (${Object.keys(options.headers ?? {}).length} headers)`, - ); - return super.dispatch(options, handler); - } -} +import { LoggingAgent } from "@homarr/common/server"; const agent = new LoggingAgent(); setGlobalDispatcher(agent); diff --git a/apps/websocket/package.json b/apps/websocket/package.json index 4ec49dc76..71c291800 100644 --- a/apps/websocket/package.json +++ b/apps/websocket/package.json @@ -34,8 +34,8 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/ws": "^8.5.13", - "eslint": "^9.16.0", + "eslint": "^9.18.0", "prettier": "^3.4.2", - "typescript": "^5.7.2" + "typescript": "^5.7.3" } } diff --git a/development/docker-run.cmd b/development/docker-run.cmd index 080de6c41..1f608898f 100644 --- a/development/docker-run.cmd +++ b/development/docker-run.cmd @@ -1 +1 @@ -docker run -p 7575:7575 -e AUTH_SECRET='secrets' homarr:latest \ No newline at end of file +docker run -p 7575:7575 homarr:latest \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..4fdb44a3a --- /dev/null +++ b/docs/README.md @@ -0,0 +1,130 @@ + +![Banner](./banner.png) + + +

+ +Latest Release (Semver) + +CI Status + + + + + + +

+ + +

+ + Demo ✨ + + • + + Install 💻 + • + + Translations 🈺 + • + + Discord 👋 + +

+ +> [!WARNING] +> This is a beta version of Homarr. You can download the old but stable version at https://github.com/ajnart/homarr/. Running this version is at your own risk. + +Simplify the management of your server with Homarr - a sleek, modern dashboard that puts all of your apps and services at your fingertips. With Homarr, you can access and control everything in one location. Homarr seamlessly integrates with the apps you've added, providing you with valuable information and giving you complete control. Installation is a breeze, and Homarr supports a wide range of deployment methods. + +
+
+ +![Features Section](./section-features.png) + +- 🖌️ Highly customizable with an extensive drag and drop grid system +- ✨ Integrates seamlessly with your favorite self-hosted applications +- 📌 Easy and fast app management - no YAML involved +- 👤 Detailed and easy to use user management with permissions and groups +- 👥 Support for single sign on via OIDC / LDAP +- 🙊 Safe encryption using BCrypt and AES-256-CBC for your valuable data +- 🕔 Realtime widget updates using WebSockets, tRPC and Redis +- 🔍 Search through thousands of data points in supported integrations or your data in Homarr using the fast built-in search +- 🦞 Icon picker with over 11K icons +- 🚀 Compatible with any major consumer hardware (x86, Raspberry Pi, old laptops, ...) and most OS (Windows, Linux, TrueNAS, Unraid) +- 🖥️ Extensive Kubernetes support with Helm for efficient scaling & high reliability + +
+
+ +![Widgets & Integrations Section](./section-widgets-and-integrations.png) + +Homarr has a [built-in collection of widgets and integrations](https://homarr.dev/docs/category/integrations), that connect to your applications and enable you to control them directly from the dashboard. + +- 📥 **Torrent clients** + - [Deluge](https://homarr.dev/docs/integrations/torrent#deluge) + - [Transmission](https://homarr.dev/docs/integrations/torrent#transmission) + - [qBittorent](https://homarr.dev/docs/integrations/torrent#qbittorrent-integration) +- 📥 **Usenet clients** + - [SABnzbd](https://homarr.dev/docs/integrations/usenet#sabnzbd) + - [NZBGet](https://homarr.dev/docs/integrations/usenet#nzbget) +- 📺 **Media servers** + - [Plex](https://homarr.dev/docs/integrations/media-server/#plex) + - [Jellyfin](https://homarr.dev/docs/integrations/media-server#jellyfin-and-emby) +- 📚 **Media collection managers** + - [Sonarr](https://homarr.dev/docs/integrations/servarr#sonarr) + - [Radarr](https://homarr.dev/docs/integrations/servarr#radarr) + - [Lidarr](https://homarr.dev/docs/integrations/servarr#lidarr) + - [Readarr](https://homarr.dev/docs/integrations/servarr#readarr) +- 🎞️ **Media request managers** + - [Overseerr](https://homarr.dev/docs/integrations/media-requester) + - [Jellyseerr](https://homarr.dev/docs/integrations/media-requester) +- 🚫 **DNS ad-blockers** + - [Pihole](https://homarr.dev/docs/integrations/dns#pihole) + - [AdGuard Home](https://homarr.dev/docs/integrations/dns#adguard-home) +- 🖥️ **Monitoring** + - [Dash.](https://homarr.dev/docs/integrations/hardware) + - [OpenMediaVault.](https://homarr.dev/docs/integrations/hardware/#openmediavault) + - [Proxmox.](https://homarr.dev/docs/integrations/hardware/#proxmox) +- 🐳 **Container management**: + - [Docker](https://homarr.dev/docs/integrations/containers) + +
+
+ +![Installation Section](./section-installation.png) + +Since we are updating Homarr very frequently, we recommend reading our official installation guides: + +

+ + Please click here for official installation instructions + +

+ +
+
+ +![Contribute Section](./section-contribute.png) + +
+ +Homarr is a free to use open source project that is maintained by volunteers and developers from all over the world. We publish under the ``Apache License 2.0`` license which allows commercial usage. We invest multiple hours daily in to providing support, developing Homarr, integrating to third party software and more. We also pay for licensing and server hosting fees. +Please consider to help us cover these costs to enable the future development of Homarr. Thank you! + +

+ + Please click here to sponsor us at OpenCollective + +

+ +You can also support us by helping with [translating the entire project](https://homarr.dev/docs/community/translations) to as many languages as possible or contributing directly to the code or documentation. Please read our [Contribution Guidelines](/CONTRIBUTING.md). All contributions, regardless of their size or scope, are welcome and highly appreciated! Thank you ❤️ + +## Sponsors +Thanks to your generous sponsors we can continue to build Homarr. Check them out for high quality and easy to use development tools. +Feel free to contact us at homarr-labs@proton.me if you wish to become a sponsor. + +[![Covered by Argos Visual Testing](https://argos-ci.com/badge-large.svg)](https://argos-ci.com?utm_source=%5Bhomarr%5D&utm_campaign=oss) diff --git a/docs/banner.png b/docs/banner.png new file mode 100644 index 000000000..823bb50b1 Binary files /dev/null and b/docs/banner.png differ diff --git a/docs/installation-button.png b/docs/installation-button.png new file mode 100644 index 000000000..991cb9b27 Binary files /dev/null and b/docs/installation-button.png differ diff --git a/docs/section-contribute.png b/docs/section-contribute.png new file mode 100644 index 000000000..3700fee95 Binary files /dev/null and b/docs/section-contribute.png differ diff --git a/docs/section-features.png b/docs/section-features.png new file mode 100644 index 000000000..b1854bf3a Binary files /dev/null and b/docs/section-features.png differ diff --git a/docs/section-installation.png b/docs/section-installation.png new file mode 100644 index 000000000..92fa4474f Binary files /dev/null and b/docs/section-installation.png differ diff --git a/docs/section-preview.png b/docs/section-preview.png new file mode 100644 index 000000000..6e43e043d Binary files /dev/null and b/docs/section-preview.png differ diff --git a/docs/section-widgets-and-integrations.png b/docs/section-widgets-and-integrations.png new file mode 100644 index 000000000..67fcbc9ea Binary files /dev/null and b/docs/section-widgets-and-integrations.png differ diff --git a/e2e/lldap.spec.ts b/e2e/lldap.spec.ts new file mode 100644 index 000000000..f9015af55 --- /dev/null +++ b/e2e/lldap.spec.ts @@ -0,0 +1,92 @@ +import { chromium } from "playwright"; +import { GenericContainer } from "testcontainers"; +import { describe, expect, test } from "vitest"; + +import { OnboardingActions } from "./shared/actions/onboarding-actions"; +import { createHomarrContainer, withLogs } from "./shared/create-homarr-container"; +import { createSqliteDbFileAsync } from "./shared/e2e-db"; + +const defaultCredentials = { + username: "admin", + password: "password", + email: "admin@homarr.dev", + group: "lldap_admin", +}; + +const ldapBase = "dc=example,dc=com"; + +describe("LLDAP authorization", () => { + test("Authorize with LLDAP successfully", async () => { + // Arrange + const lldapContainer = await createLldapContainer().start(); + const { db, localMountPath } = await createSqliteDbFileAsync(); + const homarrContainer = await createHomarrContainer({ + environment: { + AUTH_PROVIDERS: "ldap", + AUTH_LDAP_URI: `ldap://host.docker.internal:${lldapContainer.getMappedPort(3890)}`, + AUTH_LDAP_BASE: ldapBase, + AUTH_LDAP_BIND_DN: `uid=${defaultCredentials.username},ou=People,${ldapBase}`, + AUTH_LDAP_BIND_PASSWORD: defaultCredentials.password, + }, + mounts: { + "/appdata": localMountPath, + }, + }).start(); + + const browser = await chromium.launch(); + const context = await browser.newContext(); + const page = await context.newPage(); + + const onboardingActions = new OnboardingActions(page, db); + await onboardingActions.skipOnboardingAsync({ + group: defaultCredentials.group, + }); + + // Act + await page.goto(`http://${homarrContainer.getHost()}:${homarrContainer.getMappedPort(7575)}/auth/login`); + await page.getByLabel("Username").fill(defaultCredentials.username); + await page.getByLabel("Password").fill(defaultCredentials.password); + await page.locator("css=button[type='submit']").click(); + + // Assert + await page.waitForURL(`http://${homarrContainer.getHost()}:${homarrContainer.getMappedPort(7575)}`); + const users = await db.query.users.findMany({ + with: { + groups: { + with: { + group: true, + }, + }, + }, + }); + expect(users).toHaveLength(1); + const user = users[0]!; + expect(user).toEqual( + expect.objectContaining({ + name: defaultCredentials.username, + email: defaultCredentials.email, + provider: "ldap", + }), + ); + + const groups = user.groups.map((g) => g.group.name); + expect(groups).toContain(defaultCredentials.group); + + // Cleanup + await browser.close(); + await homarrContainer.stop(); + await lldapContainer.stop(); + }, 120_000); +}); + +const createLldapContainer = () => { + return withLogs( + new GenericContainer("lldap/lldap:stable").withExposedPorts(3890).withEnvironment({ + LLDAP_JWT_SECRET: "REPLACE_WITH_RANDOM", + LLDAP_KEY_SEED: "REPLACE_WITH_RANDOM", + LLDAP_LDAP_BASE_DN: ldapBase, + LLDAP_LDAP_USER_PASS: defaultCredentials.password, + LLDAP_LDAP_USER_EMAIL: defaultCredentials.email, + }), + ); +}; diff --git a/e2e/onboarding.spec.ts b/e2e/onboarding.spec.ts new file mode 100644 index 000000000..061f5e6d8 --- /dev/null +++ b/e2e/onboarding.spec.ts @@ -0,0 +1,85 @@ +import { chromium } from "playwright"; +import { describe, test } from "vitest"; + +import { OnboardingActions } from "./shared/actions/onboarding-actions"; +import { OnboardingAssertions } from "./shared/assertions/onboarding-assertions"; +import { createHomarrContainer } from "./shared/create-homarr-container"; +import { createSqliteDbFileAsync } from "./shared/e2e-db"; + +describe("Onboarding", () => { + test("Credentials onboarding should be successful", async () => { + // Arrange + const { db, localMountPath } = await createSqliteDbFileAsync(); + const homarrContainer = await createHomarrContainer({ + mounts: { + "/appdata": localMountPath, + }, + }).start(); + + const browser = await chromium.launch(); + const context = await browser.newContext(); + const page = await context.newPage(); + const actions = new OnboardingActions(page, db); + const assertions = new OnboardingAssertions(page, db); + + // Act + await page.goto(`http://${homarrContainer.getHost()}:${homarrContainer.getMappedPort(7575)}`); + await actions.startOnboardingAsync("scratch"); + await actions.processUserStepAsync({ + username: "admin", + password: "Comp(exP4sswOrd", + confirmPassword: "Comp(exP4sswOrd", + }); + await actions.processSettingsStepAsync(); + + // Assert + await assertions.assertFinishStepVisibleAsync(); + await assertions.assertUserAndAdminGroupInsertedAsync("admin"); + await assertions.assertDbOnboardingStepAsync("finish"); + + // Cleanup + await browser.close(); + await homarrContainer.stop(); + }, 60_000); + + test("External provider onboarding setup should be successful", async () => { + // Arrange + const { db, localMountPath } = await createSqliteDbFileAsync(); + const homarrContainer = await createHomarrContainer({ + environment: { + AUTH_PROVIDERS: "ldap", + AUTH_LDAP_URI: "ldap://host.docker.internal:3890", + AUTH_LDAP_BASE: "", + AUTH_LDAP_BIND_DN: "", + AUTH_LDAP_BIND_PASSWORD: "", + }, + mounts: { + "/appdata": localMountPath, + }, + }).start(); + const externalGroupName = "oidc-admins"; + + const browser = await chromium.launch(); + const context = await browser.newContext(); + const page = await context.newPage(); + const actions = new OnboardingActions(page, db); + const assertions = new OnboardingAssertions(page, db); + + // Act + await page.goto(`http://${homarrContainer.getHost()}:${homarrContainer.getMappedPort(7575)}`); + await actions.startOnboardingAsync("scratch"); + await actions.processExternalGroupStepAsync({ + name: externalGroupName, + }); + await actions.processSettingsStepAsync(); + + // Assert + await assertions.assertFinishStepVisibleAsync(); + await assertions.assertExternalGroupInsertedAsync(externalGroupName); + await assertions.assertDbOnboardingStepAsync("finish"); + + // Cleanup + await browser.close(); + await homarrContainer.stop(); + }, 60_000); +}); diff --git a/e2e/shared/actions/onboarding-actions.ts b/e2e/shared/actions/onboarding-actions.ts new file mode 100644 index 000000000..8362a46a5 --- /dev/null +++ b/e2e/shared/actions/onboarding-actions.ts @@ -0,0 +1,53 @@ +import { createId } from "@paralleldrive/cuid2"; +import type { Page } from "playwright"; + +import * as sqliteSchema from "../../../packages/db/schema/sqlite"; +import type { SqliteDatabase } from "../e2e-db"; + +export class OnboardingActions { + private readonly page: Page; + private readonly db: SqliteDatabase; + + constructor(page: Page, db: SqliteDatabase) { + this.page = page; + this.db = db; + } + + public async skipOnboardingAsync(input?: { group?: string }) { + await this.db.update(sqliteSchema.onboarding).set({ + step: "finish", + }); + + if (input?.group) { + await this.db.insert(sqliteSchema.groups).values({ + id: createId(), + name: input.group, + }); + } + } + + public async startOnboardingAsync(type: "scratch" | "before 1.0") { + await this.page.locator("button", { hasText: type }).click(); + } + + public async processUserStepAsync(input: { username: string; password: string; confirmPassword: string }) { + await this.page.waitForSelector("text=administrator user"); + + await this.page.getByLabel("Username").fill(input.username); + await this.page.getByLabel("Password", { exact: true }).fill(input.password); + await this.page.getByLabel("Confirm password").fill(input.confirmPassword); + + await this.page.locator("css=button[type='submit']").click(); + } + + public async processExternalGroupStepAsync(input: { name: string }) { + await this.page.waitForSelector("text=external provider"); + await this.page.locator("input").fill(input.name); + await this.page.locator("css=button[type='submit']").click(); + } + + public async processSettingsStepAsync() { + await this.page.waitForSelector("text=Analytics"); + await this.page.locator("css=button[type='submit']").click(); + } +} diff --git a/e2e/shared/assertions/onboarding-assertions.ts b/e2e/shared/assertions/onboarding-assertions.ts new file mode 100644 index 000000000..a2f9ccb2f --- /dev/null +++ b/e2e/shared/assertions/onboarding-assertions.ts @@ -0,0 +1,62 @@ +import { eq } from "drizzle-orm"; +import type { Page } from "playwright"; +import { expect } from "vitest"; + +import * as sqliteSchema from "../../../packages/db/schema/sqlite"; +import { OnboardingStep } from "../../../packages/definitions/src"; +import { credentialsAdminGroup } from "../../../packages/definitions/src/group"; +import type { SqliteDatabase } from "../e2e-db"; + +export class OnboardingAssertions { + private readonly page: Page; + private readonly db: SqliteDatabase; + + constructor(page: Page, db: SqliteDatabase) { + this.page = page; + this.db = db; + } + + public async assertDbOnboardingStepAsync(expectedStep: OnboardingStep) { + const onboarding = await this.db.query.onboarding.findFirst(); + expect(onboarding?.step).toEqual(expectedStep); + } + + public async assertUserAndAdminGroupInsertedAsync(expectedUsername: string) { + const users = await this.db.query.users.findMany({ + with: { + groups: { + with: { + group: { + with: { + permissions: true, + }, + }, + }, + }, + }, + }); + + const user = users.find((u) => u.name === expectedUsername); + expect(user).toBeDefined(); + + const adminGroup = user!.groups.find((g) => g.group.name === credentialsAdminGroup); + expect(adminGroup).toBeDefined(); + expect(adminGroup!.group.permissions).toEqual([expect.objectContaining({ permission: "admin" })]); + } + + public async assertExternalGroupInsertedAsync(expectedGroupName: string) { + const group = await this.db.query.groups.findFirst({ + where: eq(sqliteSchema.groups.name, expectedGroupName), + with: { + permissions: true, + }, + }); + + expect(group).toBeDefined(); + expect(group!.permissions).toEqual([expect.objectContaining({ permission: "admin" })]); + } + + public async assertFinishStepVisibleAsync() { + await this.page.waitForSelector("text=completed the setup", { timeout: 5000 }); + } +} diff --git a/e2e/shared/create-homarr-container.ts b/e2e/shared/create-homarr-container.ts index 84cbcc711..7e5bcd5c4 100644 --- a/e2e/shared/create-homarr-container.ts +++ b/e2e/shared/create-homarr-container.ts @@ -1,14 +1,51 @@ import { GenericContainer, Wait } from "testcontainers"; +import { Environment } from "testcontainers/build/types"; -export const createHomarrContainer = () => { +export const createHomarrContainer = ( + options: { + environment?: Environment; + mounts?: { + "/appdata"?: string; + "/var/run/docker.sock"?: string; + }; + } = {}, +) => { if (!process.env.CI) { throw new Error("This test should only be run in CI or with a homarr image named 'homarr-e2e'"); } - return new GenericContainer("homarr-e2e") - .withEnvironment({ - AUTH_SECRET: "secret", - }) + const container = new GenericContainer("homarr-e2e") .withExposedPorts(7575) - .withWaitStrategy(Wait.forHttp("/api/health/ready", 7575)); + .withEnvironment({ + ...options.environment, + SECRET_ENCRYPTION_KEY: "0".repeat(64), + }) + .withBindMounts( + Object.entries(options.mounts ?? {}) + .filter((item) => item?.[0] !== undefined) + .map(([container, local]) => ({ + source: local, + target: container, + })), + ) + .withWaitStrategy(Wait.forHttp("/api/health/ready", 7575)) + .withExtraHosts([ + { + // This enabled the usage of host.docker.internal as hostname in the container + host: "host.docker.internal", + ipAddress: "host-gateway", + }, + ]); + + return withLogs(container); +}; + +export const withLogs = (container: GenericContainer) => { + container.withLogConsumer((stream) => + stream + .on("data", (line) => console.log(line)) + .on("err", (line) => console.error(line)) + .on("end", () => console.log("Stream closed")), + ); + return container; }; diff --git a/e2e/shared/e2e-db.ts b/e2e/shared/e2e-db.ts new file mode 100644 index 000000000..0abc87823 --- /dev/null +++ b/e2e/shared/e2e-db.ts @@ -0,0 +1,32 @@ +import { mkdir } from "fs/promises"; +import path from "path"; +import { createId } from "@paralleldrive/cuid2"; +import Database from "better-sqlite3"; +import { BetterSQLite3Database, drizzle } from "drizzle-orm/better-sqlite3"; +import { migrate } from "drizzle-orm/better-sqlite3/migrator"; + +import * as sqliteSchema from "../../packages/db/schema/sqlite"; + +export const createSqliteDbFileAsync = async () => { + const localMountPath = path.join(__dirname, "tmp", createId()); + await mkdir(path.join(localMountPath, "db"), { recursive: true }); + + const localDbUrl = path.join(localMountPath, "db", "db.sqlite"); + + const connection = new Database(localDbUrl); + const db = drizzle(connection, { + schema: sqliteSchema, + casing: "snake_case", + }); + + await migrate(db, { + migrationsFolder: path.join(__dirname, "..", "..", "packages", "db", "migrations", "sqlite"), + }); + + return { + db, + localMountPath, + }; +}; + +export type SqliteDatabase = BetterSQLite3Database; diff --git a/nginx.conf b/nginx.conf index 25e571394..dbfeba55a 100644 --- a/nginx.conf +++ b/nginx.conf @@ -21,7 +21,7 @@ http { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; } } } \ No newline at end of file diff --git a/package.json b/package.json index 172c86c67..69144e093 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "homarr", + "version": "1.0.0-beta.12", "private": true, "scripts": { "build": "cross-env CI=true turbo build", @@ -20,36 +21,49 @@ "lint:fix": "turbo lint --continue -- --fix --cache --cache-location node_modules/.cache/.eslintcache", "lint:ws": "pnpm dlx sherif@latest", "package:new": "turbo gen init", - "test": "cross-env NODE_ENV=development vitest run --exclude e2e --coverage.enabled ", - "test:e2e": "cross-env NODE_ENV=development vitest e2e", - "test:ui": "cross-env NODE_ENV=development vitest --exclude e2e --ui --coverage.enabled", + "release": "semantic-release", + "start": "concurrently \"pnpm with-env node apps/tasks/tasks.cjs\" \"pnpm with-env node apps/websocket/wssServer.cjs\" \"pnpm -F nextjs start\"", + "test": "cross-env NODE_ENV=development CI=true vitest run --exclude e2e --coverage.enabled ", + "test:e2e": "cross-env NODE_ENV=development CI=true vitest e2e", + "test:ui": "cross-env NODE_ENV=development CI=true vitest --exclude e2e --ui --coverage.enabled", "typecheck": "turbo typecheck", "with-env": "dotenv -e .env --" }, "prettier": "@homarr/prettier-config", "devDependencies": { "@homarr/prettier-config": "workspace:^0.1.0", + "@semantic-release/changelog": "^6.0.3", + "@semantic-release/commit-analyzer": "^13.0.1", + "@semantic-release/git": "^10.0.1", + "@semantic-release/github": "^11.0.1", + "@semantic-release/npm": "^12.0.1", + "@semantic-release/release-notes-generator": "^14.0.3", "@turbo/gen": "^2.3.3", "@vitejs/plugin-react": "^4.3.4", "@vitest/coverage-v8": "^2.1.8", "@vitest/ui": "^2.1.8", + "conventional-changelog-conventionalcommits": "^8.0.0", "cross-env": "^7.0.3", - "jsdom": "^25.0.1", + "jsdom": "^26.0.0", "prettier": "^3.4.2", + "semantic-release": "^24.2.1", "testcontainers": "^10.16.0", "turbo": "^2.3.3", - "typescript": "^5.7.2", + "typescript": "^5.7.3", "vite-tsconfig-paths": "^5.1.4", "vitest": "^2.1.8" }, - "packageManager": "pnpm@9.15.0", + "packageManager": "pnpm@9.15.4", "engines": { - "node": ">=22.12.0" + "node": ">=22.13.0" }, "pnpm": { + "allowNonAppliedPatches": true, + "overrides": { + "proxmox-api>undici": "7.2.3" + }, "patchedDependencies": { "pretty-print-error": "patches/pretty-print-error.patch" - }, - "allowNonAppliedPatches": true + } } } diff --git a/packages/analytics/package.json b/packages/analytics/package.json index e11c94611..7d454f655 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -32,7 +32,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/analytics/src/send-server-analytics.ts b/packages/analytics/src/send-server-analytics.ts index 51b3741ae..e09bd71da 100644 --- a/packages/analytics/src/send-server-analytics.ts +++ b/packages/analytics/src/send-server-analytics.ts @@ -3,7 +3,7 @@ import { Umami } from "@umami/node"; import { count, db } from "@homarr/db"; import { getServerSettingByKeyAsync } from "@homarr/db/queries"; -import { integrations, items, users } from "@homarr/db/schema/sqlite"; +import { integrations, items, users } from "@homarr/db/schema"; import { logger } from "@homarr/log"; import type { defaultServerSettings } from "@homarr/server-settings"; diff --git a/packages/api/package.json b/packages/api/package.json index e0632a560..3ad6af827 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -8,7 +8,8 @@ ".": "./src/index.ts", "./client": "./src/client.ts", "./server": "./src/server.ts", - "./websocket": "./src/websocket.ts" + "./websocket": "./src/websocket.ts", + "./shared": "./src/shared.ts" }, "main": "./index.ts", "types": "./index.ts", @@ -21,12 +22,14 @@ "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/auth": "workspace:^0.1.0", + "@homarr/certificates": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0", "@homarr/cron-job-runner": "workspace:^0.1.0", "@homarr/cron-job-status": "workspace:^0.1.0", "@homarr/cron-jobs": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", + "@homarr/icons": "workspace:^0.1.0", "@homarr/integrations": "workspace:^0.1.0", "@homarr/log": "workspace:^", "@homarr/old-import": "workspace:^0.1.0", @@ -39,19 +42,21 @@ "@trpc/client": "next", "@trpc/react-query": "next", "@trpc/server": "next", - "dockerode": "^4.0.2", - "next": "^14.2.20", - "react": "^19.0.0", + "dockerode": "4.0.2", + "lodash.clonedeep": "^4.5.0", + "next": "15.1.4", + "react": "19.0.0", + "react-dom": "19.0.0", "superjson": "2.2.2", - "trpc-to-openapi": "^2.1.0" + "trpc-to-openapi": "^2.1.2" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "@types/dockerode": "^3.3.32", - "eslint": "^9.16.0", + "@types/dockerode": "^3.3.34", + "eslint": "^9.18.0", "prettier": "^3.4.2", - "typescript": "^5.7.2" + "typescript": "^5.7.3" } } diff --git a/packages/api/src/client.ts b/packages/api/src/client.ts index b40cdd412..3bac46dc7 100644 --- a/packages/api/src/client.ts +++ b/packages/api/src/client.ts @@ -1,7 +1,11 @@ -import { createTRPCClient, createTRPCReact, httpLink } from "@trpc/react-query"; +"use client"; + +import { createTRPCClient, httpLink } from "@trpc/client"; +import { createTRPCReact } from "@trpc/react-query"; import SuperJSON from "superjson"; import type { AppRouter } from "."; +import { createHeadersCallbackForSource } from "./shared"; export const clientApi = createTRPCReact(); export const fetchApi = createTRPCClient({ @@ -16,7 +20,6 @@ export const fetchApi = createTRPCClient({ function getBaseUrl() { if (typeof window !== "undefined") return window.location.origin; - if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; return `http://localhost:${process.env.PORT ?? 3000}`; } @@ -27,42 +30,3 @@ function getBaseUrl() { export function getTrpcUrl() { return `${getBaseUrl()}/api/trpc`; } - -/** - * Creates a headers callback for a given source - * It will set the x-trpc-source header and cookies if needed - * @param source trpc source request comes from - * @returns headers callback - */ -export function createHeadersCallbackForSource(source: string) { - return async () => { - const headers = new Headers(); - headers.set("x-trpc-source", source); - - const cookies = await importCookiesAsync(); - // We need to set cookie for ssr requests (for example with useSuspenseQuery or middleware) - if (cookies) { - headers.set("cookie", cookies); - } - - return headers; - }; -} - -/** - * This is a workarround as cookies are not passed to the server - * when using useSuspenseQuery or middleware - * @returns cookie string on server or null on client - */ -async function importCookiesAsync() { - if (typeof window === "undefined") { - return await import("next/headers").then(({ cookies }) => - cookies() - .getAll() - .map(({ name, value }) => `${name}=${value}`) - .join(";"), - ); - } - - return null; -} diff --git a/packages/api/src/middlewares/integration.ts b/packages/api/src/middlewares/integration.ts index b6d715a56..d2a84f641 100644 --- a/packages/api/src/middlewares/integration.ts +++ b/packages/api/src/middlewares/integration.ts @@ -7,7 +7,7 @@ import { decryptSecret } from "@homarr/common/server"; import type { AtLeastOneOf } from "@homarr/common/types"; import type { Database } from "@homarr/db"; import { and, eq, inArray } from "@homarr/db"; -import { integrations } from "@homarr/db/schema/sqlite"; +import { integrations } from "@homarr/db/schema"; import type { IntegrationKind } from "@homarr/definitions"; import { z } from "@homarr/validation"; diff --git a/packages/api/src/middlewares/item.ts b/packages/api/src/middlewares/item.ts index 78cc623db..79d93a463 100644 --- a/packages/api/src/middlewares/item.ts +++ b/packages/api/src/middlewares/item.ts @@ -1,7 +1,7 @@ import { TRPCError } from "@trpc/server"; import { and, eq } from "@homarr/db"; -import { items } from "@homarr/db/schema/sqlite"; +import { items } from "@homarr/db/schema"; import type { WidgetKind } from "@homarr/definitions"; import { z } from "@homarr/validation"; diff --git a/packages/api/src/root.ts b/packages/api/src/root.ts index 1f414de47..a0c04f460 100644 --- a/packages/api/src/root.ts +++ b/packages/api/src/root.ts @@ -1,18 +1,22 @@ import { apiKeysRouter } from "./router/apiKeys"; import { appRouter as innerAppRouter } from "./router/app"; import { boardRouter } from "./router/board"; +import { certificateRouter } from "./router/certificates/certificate-router"; import { cronJobsRouter } from "./router/cron-jobs"; import { dockerRouter } from "./router/docker/docker-router"; import { groupRouter } from "./router/group"; import { homeRouter } from "./router/home"; import { iconsRouter } from "./router/icons"; +import { importRouter } from "./router/import/import-router"; import { integrationRouter } from "./router/integration/integration-router"; import { inviteRouter } from "./router/invite"; import { locationRouter } from "./router/location"; import { logRouter } from "./router/log"; import { mediaRouter } from "./router/medias/media-router"; +import { onboardRouter } from "./router/onboard/onboard-router"; import { searchEngineRouter } from "./router/search-engine/search-engine-router"; import { serverSettingsRouter } from "./router/serverSettings"; +import { updateCheckerRouter } from "./router/update-checker"; import { userRouter } from "./router/user"; import { widgetRouter } from "./router/widgets"; import { createTRPCRouter } from "./trpc"; @@ -29,12 +33,16 @@ export const appRouter = createTRPCRouter({ location: locationRouter, log: logRouter, icon: iconsRouter, + import: importRouter, + onboard: onboardRouter, home: homeRouter, docker: dockerRouter, serverSettings: serverSettingsRouter, cronJobs: cronJobsRouter, apiKeys: apiKeysRouter, media: mediaRouter, + updateChecker: updateCheckerRouter, + certificates: certificateRouter, }); // export type definition of API diff --git a/packages/api/src/router/apiKeys.ts b/packages/api/src/router/apiKeys.ts index 715e85906..da903d695 100644 --- a/packages/api/src/router/apiKeys.ts +++ b/packages/api/src/router/apiKeys.ts @@ -1,7 +1,7 @@ import { createSaltAsync, hashPasswordAsync } from "@homarr/auth"; import { generateSecureRandomToken } from "@homarr/common/server"; import { createId, db } from "@homarr/db"; -import { apiKeys } from "@homarr/db/schema/sqlite"; +import { apiKeys } from "@homarr/db/schema"; import { createTRPCRouter, permissionRequiredProcedure } from "../trpc"; diff --git a/packages/api/src/router/app.ts b/packages/api/src/router/app.ts index 918559c3a..43cc24031 100644 --- a/packages/api/src/router/app.ts +++ b/packages/api/src/router/app.ts @@ -1,15 +1,38 @@ import { TRPCError } from "@trpc/server"; import { asc, createId, eq, inArray, like } from "@homarr/db"; -import { apps } from "@homarr/db/schema/sqlite"; +import { apps } from "@homarr/db/schema"; import { selectAppSchema } from "@homarr/db/validationSchemas"; +import { getIconForName } from "@homarr/icons"; import { validation, z } from "@homarr/validation"; import { convertIntersectionToZodObject } from "../schema-merger"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../trpc"; import { canUserSeeAppAsync } from "./app/app-access-control"; +const defaultIcon = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/homarr.svg"; + export const appRouter = createTRPCRouter({ + getPaginated: protectedProcedure + .input(validation.common.paginated) + .output(z.object({ items: z.array(selectAppSchema), totalCount: z.number() })) + .meta({ openapi: { method: "GET", path: "/api/apps/paginated", tags: ["apps"], protect: true } }) + .query(async ({ input, ctx }) => { + const whereQuery = input.search ? like(apps.name, `%${input.search.trim()}%`) : undefined; + const totalCount = await ctx.db.$count(apps, whereQuery); + + const dbApps = await ctx.db.query.apps.findMany({ + limit: input.pageSize, + offset: (input.page - 1) * input.pageSize, + where: whereQuery, + orderBy: asc(apps.name), + }); + + return { + items: dbApps, + totalCount, + }; + }), all: protectedProcedure .input(z.void()) .output(z.array(selectAppSchema)) @@ -98,6 +121,21 @@ export const appRouter = createTRPCRouter({ href: input.href, }); }), + createMany: permissionRequiredProcedure + .requiresPermission("app-create") + .input(validation.app.createMany) + .output(z.void()) + .mutation(async ({ ctx, input }) => { + await ctx.db.insert(apps).values( + input.map((app) => ({ + id: createId(), + name: app.name, + description: app.description, + iconUrl: app.iconUrl ?? getIconForName(ctx.db, app.name).sync()?.url ?? defaultIcon, + href: app.href, + })), + ); + }), update: permissionRequiredProcedure .requiresPermission("app-modify-all") .input(convertIntersectionToZodObject(validation.app.edit)) diff --git a/packages/api/src/router/app/app-access-control.ts b/packages/api/src/router/app/app-access-control.ts index b395cea09..d4254cb75 100644 --- a/packages/api/src/router/app/app-access-control.ts +++ b/packages/api/src/router/app/app-access-control.ts @@ -2,7 +2,7 @@ import SuperJSON from "superjson"; import type { Session } from "@homarr/auth"; import { db, eq, or } from "@homarr/db"; -import { items } from "@homarr/db/schema/sqlite"; +import { items } from "@homarr/db/schema"; import type { WidgetComponentProps } from "../../../../widgets/src"; diff --git a/packages/api/src/router/board.ts b/packages/api/src/router/board.ts index accbf7aa3..72ae2bfd2 100644 --- a/packages/api/src/router/board.ts +++ b/packages/api/src/router/board.ts @@ -2,8 +2,9 @@ import { TRPCError } from "@trpc/server"; import superjson from "superjson"; import { constructBoardPermissions } from "@homarr/auth/shared"; -import type { Database, SQL } from "@homarr/db"; -import { and, createId, eq, inArray, like, or } from "@homarr/db"; +import type { DeviceType } from "@homarr/common/server"; +import type { Database, InferInsertModel, InferSelectModel, SQL } from "@homarr/db"; +import { and, createId, eq, handleTransactionsAsync, inArray, like, or } from "@homarr/db"; import { getServerSettingByKeyAsync } from "@homarr/db/queries"; import { boardGroupPermissions, @@ -11,19 +12,21 @@ import { boardUserPermissions, groupMembers, groupPermissions, + integrationGroupPermissions, integrationItems, + integrationUserPermissions, items, sections, users, -} from "@homarr/db/schema/sqlite"; +} from "@homarr/db/schema"; import type { WidgetKind } from "@homarr/definitions"; import { getPermissionsWithParents, widgetKinds } from "@homarr/definitions"; -import { importAsync } from "@homarr/old-import"; +import { importOldmarrAsync } from "@homarr/old-import"; +import { importJsonFileSchema } from "@homarr/old-import/shared"; import { oldmarrConfigSchema } from "@homarr/old-schema"; import type { BoardItemAdvancedOptions } from "@homarr/validation"; -import { createSectionSchema, sharedItemSchema, validation, z } from "@homarr/validation"; +import { createSectionSchema, sharedItemSchema, validation, z, zodUnionFromArray } from "@homarr/validation"; -import { zodUnionFromArray } from "../../../validation/src/enums"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../trpc"; import { throwIfActionForbiddenAsync } from "./board/board-access"; @@ -119,6 +122,7 @@ export const boardRouter = createTRPCRouter({ return dbBoards.map((board) => ({ ...board, isHome: currentUserWhenPresent?.homeBoardId === board.id, + isMobileHome: currentUserWhenPresent?.mobileHomeBoardId === board.id, })); }), search: publicProcedure @@ -192,6 +196,7 @@ export const boardRouter = createTRPCRouter({ logoImageUrl: board.logoImageUrl, permissions: constructBoardPermissions(board, ctx.session), isHome: currentUserWhenPresent?.homeBoardId === board.id, + isMobileHome: currentUserWhenPresent?.mobileHomeBoardId === board.id, })); }), createBoard: permissionRequiredProcedure @@ -199,21 +204,180 @@ export const boardRouter = createTRPCRouter({ .input(validation.board.create) .mutation(async ({ ctx, input }) => { const boardId = createId(); - await ctx.db.transaction(async (transaction) => { - await transaction.insert(boards).values({ - id: boardId, - name: input.name, - isPublic: input.isPublic, - columnCount: input.columnCount, - creatorId: ctx.session.user.id, - }); - await transaction.insert(sections).values({ - id: createId(), - kind: "empty", - xOffset: 0, - yOffset: 0, - boardId, + await handleTransactionsAsync(ctx.db, { + async handleAsync(db, schema) { + await db.transaction(async (transaction) => { + await transaction.insert(schema.boards).values({ + id: boardId, + name: input.name, + isPublic: input.isPublic, + columnCount: input.columnCount, + creatorId: ctx.session.user.id, + }); + await transaction.insert(schema.sections).values({ + id: createId(), + kind: "empty", + xOffset: 0, + yOffset: 0, + boardId, + }); + }); + }, + handleSync(db) { + db.transaction((transaction) => { + transaction + .insert(boards) + .values({ + id: boardId, + name: input.name, + isPublic: input.isPublic, + columnCount: input.columnCount, + creatorId: ctx.session.user.id, + }) + .run(); + transaction + .insert(sections) + .values({ + id: createId(), + kind: "empty", + xOffset: 0, + yOffset: 0, + boardId, + }) + .run(); + }); + }, + }); + }), + duplicateBoard: permissionRequiredProcedure + .requiresPermission("board-create") + .input(validation.board.duplicate) + .mutation(async ({ ctx, input }) => { + await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "view"); + await noBoardWithSimilarNameAsync(ctx.db, input.name); + + const board = await ctx.db.query.boards.findFirst({ + where: eq(boards.id, input.id), + with: { + sections: { + with: { + items: { + with: { + integrations: true, + }, + }, + }, + }, + }, + }); + + if (!board) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Board not found", }); + } + + const { sections: boardSections, ...boardProps } = board; + + const newBoardId = createId(); + const sectionMap = new Map(boardSections.map((section) => [section.id, createId()])); + const sectionsToInsert: InferInsertModel[] = boardSections.map(({ items: _, ...section }) => ({ + ...section, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + id: sectionMap.get(section.id)!, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + parentSectionId: section.parentSectionId ? sectionMap.get(section.parentSectionId)! : null, + boardId: newBoardId, + })); + const flatItems = boardSections.flatMap((section) => section.items); + const itemMap = new Map(flatItems.map((item) => [item.id, createId()])); + const itemsToInsert: InferInsertModel[] = flatItems.map(({ integrations: _, ...item }) => ({ + ...item, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + id: itemMap.get(item.id)!, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + sectionId: sectionMap.get(item.sectionId)!, + })); + + // Creates a list with all integration ids the user has access to + const hasAccessForAll = ctx.session.user.permissions.includes("integration-use-all"); + const integrationIdsWithAccess = hasAccessForAll + ? [] + : await ctx.db + .selectDistinct({ + id: integrationGroupPermissions.integrationId, + }) + .from(integrationGroupPermissions) + .leftJoin(groupMembers, eq(integrationGroupPermissions.groupId, groupMembers.groupId)) + .where(eq(groupMembers.userId, ctx.session.user.id)) + .union( + ctx.db + .selectDistinct({ id: integrationUserPermissions.integrationId }) + .from(integrationUserPermissions) + .where(eq(integrationUserPermissions.userId, ctx.session.user.id)), + ) + .then((result) => result.map((row) => row.id)); + + const itemIntegrationsToInsert = flatItems.flatMap((item) => + item.integrations + // Restrict integrations to only those the user has access to + .filter(({ integrationId }) => integrationIdsWithAccess.includes(integrationId) || hasAccessForAll) + .map((integration) => ({ + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + itemId: itemMap.get(item.id)!, + integrationId: integration.integrationId, + })), + ); + + await handleTransactionsAsync(ctx.db, { + async handleAsync(db, schema) { + await db.transaction(async (transaction) => { + transaction.insert(schema.boards).values({ + ...boardProps, + id: newBoardId, + name: input.name, + creatorId: ctx.session.user.id, + }); + + if (sectionsToInsert.length > 0) { + await transaction.insert(schema.sections).values(sectionsToInsert); + } + + if (itemsToInsert.length > 0) { + await transaction.insert(schema.items).values(itemsToInsert); + } + + if (itemIntegrationsToInsert.length > 0) { + await transaction.insert(schema.integrationItems).values(itemIntegrationsToInsert); + } + }); + }, + handleSync(db) { + db.transaction((transaction) => { + transaction + .insert(boards) + .values({ + ...boardProps, + id: newBoardId, + name: input.name, + creatorId: ctx.session.user.id, + }) + .run(); + + if (sectionsToInsert.length > 0) { + transaction.insert(sections).values(sectionsToInsert).run(); + } + + if (itemsToInsert.length > 0) { + transaction.insert(items).values(itemsToInsert).run(); + } + + if (itemIntegrationsToInsert.length > 0) { + transaction.insert(integrationItems).values(itemIntegrationsToInsert).run(); + } + }); + }, }); }), renameBoard: protectedProcedure.input(validation.board.rename).mutation(async ({ ctx, input }) => { @@ -229,7 +393,10 @@ export const boardRouter = createTRPCRouter({ await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "full"); const boardSettings = await getServerSettingByKeyAsync(ctx.db, "board"); - if (input.visibility !== "public" && boardSettings.homeBoardId === input.id) { + if ( + input.visibility !== "public" && + (boardSettings.homeBoardId === input.id || boardSettings.mobileHomeBoardId === input.id) + ) { throw new TRPCError({ code: "BAD_REQUEST", message: "Cannot make home board private", @@ -251,30 +418,30 @@ export const boardRouter = createTRPCRouter({ await ctx.db.update(users).set({ homeBoardId: input.id }).where(eq(users.id, ctx.session.user.id)); }), + setMobileHomeBoard: protectedProcedure.input(z.object({ id: z.string() })).mutation(async ({ ctx, input }) => { + await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "view"); + + await ctx.db.update(users).set({ mobileHomeBoardId: input.id }).where(eq(users.id, ctx.session.user.id)); + }), getHomeBoard: publicProcedure.query(async ({ ctx }) => { const userId = ctx.session?.user.id; const user = userId - ? await ctx.db.query.users.findFirst({ + ? ((await ctx.db.query.users.findFirst({ where: eq(users.id, userId), - }) + })) ?? null) : null; - // 1. user home board, 2. home board, 3. not found - let boardWhere: SQL | null = null; - if (user?.homeBoardId) { - boardWhere = eq(boards.id, user.homeBoardId); - } else { - const boardSettings = await getServerSettingByKeyAsync(ctx.db, "board"); - boardWhere = boardSettings.homeBoardId ? eq(boards.id, boardSettings.homeBoardId) : null; - } + const homeBoardId = await getHomeIdBoardAsync(ctx.db, user, ctx.deviceType); - if (!boardWhere) { + if (!homeBoardId) { throw new TRPCError({ code: "NOT_FOUND", message: "No home board found", }); } + const boardWhere = eq(boards.id, homeBoardId); + await throwIfActionForbiddenAsync(ctx, boardWhere, "view"); return await getFullBoardWithWhereAsync(ctx.db, boardWhere, ctx.session?.user.id ?? null); @@ -321,148 +488,313 @@ export const boardRouter = createTRPCRouter({ saveBoard: protectedProcedure.input(validation.board.save).mutation(async ({ input, ctx }) => { await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.id), "modify"); - await ctx.db.transaction(async (transaction) => { - const dbBoard = await getFullBoardWithWhereAsync(transaction, eq(boards.id, input.id), ctx.session.user.id); + const dbBoard = await getFullBoardWithWhereAsync(ctx.db, eq(boards.id, input.id), ctx.session.user.id); - const addedSections = filterAddedItems(input.sections, dbBoard.sections); + await handleTransactionsAsync(ctx.db, { + async handleAsync(db, schema) { + await db.transaction(async (transaction) => { + const addedSections = filterAddedItems(input.sections, dbBoard.sections); - if (addedSections.length > 0) { - await transaction.insert(sections).values( - addedSections.map((section) => ({ - id: section.id, - kind: section.kind, - yOffset: section.yOffset, - xOffset: section.kind === "dynamic" ? section.xOffset : 0, - height: "height" in section ? section.height : null, - width: "width" in section ? section.width : null, - parentSectionId: "parentSectionId" in section ? section.parentSectionId : null, - name: "name" in section ? section.name : null, - boardId: dbBoard.id, - })), - ); - } + if (addedSections.length > 0) { + await transaction.insert(schema.sections).values( + addedSections.map((section) => ({ + id: section.id, + kind: section.kind, + yOffset: section.yOffset, + xOffset: section.kind === "dynamic" ? section.xOffset : 0, + height: "height" in section ? section.height : null, + width: "width" in section ? section.width : null, + parentSectionId: "parentSectionId" in section ? section.parentSectionId : null, + name: "name" in section ? section.name : null, + boardId: dbBoard.id, + })), + ); + } - const inputItems = input.sections.flatMap((section) => - section.items.map((item) => ({ ...item, sectionId: section.id })), - ); - const dbItems = dbBoard.sections.flatMap((section) => - section.items.map((item) => ({ ...item, sectionId: section.id })), - ); - - const addedItems = filterAddedItems(inputItems, dbItems); - - if (addedItems.length > 0) { - await transaction.insert(items).values( - addedItems.map((item) => ({ - id: item.id, - kind: item.kind, - height: item.height, - width: item.width, - xOffset: item.xOffset, - yOffset: item.yOffset, - options: superjson.stringify(item.options), - advancedOptions: superjson.stringify(item.advancedOptions), - sectionId: item.sectionId, - })), - ); - } - - const inputIntegrationRelations = inputItems.flatMap(({ integrationIds, id: itemId }) => - integrationIds.map((integrationId) => ({ - integrationId, - itemId, - })), - ); - const dbIntegrationRelations = dbItems.flatMap(({ integrationIds, id: itemId }) => - integrationIds.map((integrationId) => ({ - integrationId, - itemId, - })), - ); - const addedIntegrationRelations = inputIntegrationRelations.filter( - (inputRelation) => - !dbIntegrationRelations.some( - (dbRelation) => - dbRelation.itemId === inputRelation.itemId && dbRelation.integrationId === inputRelation.integrationId, - ), - ); - - if (addedIntegrationRelations.length > 0) { - await transaction.insert(integrationItems).values( - addedIntegrationRelations.map((relation) => ({ - itemId: relation.itemId, - integrationId: relation.integrationId, - })), - ); - } - - const updatedItems = filterUpdatedItems(inputItems, dbItems); - - for (const item of updatedItems) { - await transaction - .update(items) - .set({ - kind: item.kind, - height: item.height, - width: item.width, - xOffset: item.xOffset, - yOffset: item.yOffset, - options: superjson.stringify(item.options), - advancedOptions: superjson.stringify(item.advancedOptions), - sectionId: item.sectionId, - }) - .where(eq(items.id, item.id)); - } - - const updatedSections = filterUpdatedItems(input.sections, dbBoard.sections); - - for (const section of updatedSections) { - const prev = dbBoard.sections.find((dbSection) => dbSection.id === section.id); - await transaction - .update(sections) - .set({ - yOffset: section.yOffset, - xOffset: section.xOffset, - height: prev?.kind === "dynamic" && "height" in section ? section.height : null, - width: prev?.kind === "dynamic" && "width" in section ? section.width : null, - parentSectionId: prev?.kind === "dynamic" && "parentSectionId" in section ? section.parentSectionId : null, - name: prev?.kind === "category" && "name" in section ? section.name : null, - }) - .where(eq(sections.id, section.id)); - } - - const removedIntegrationRelations = dbIntegrationRelations.filter( - (dbRelation) => - !inputIntegrationRelations.some( - (inputRelation) => - dbRelation.itemId === inputRelation.itemId && dbRelation.integrationId === inputRelation.integrationId, - ), - ); - - for (const relation of removedIntegrationRelations) { - await transaction - .delete(integrationItems) - .where( - and( - eq(integrationItems.itemId, relation.itemId), - eq(integrationItems.integrationId, relation.integrationId), - ), + const inputItems = input.sections.flatMap((section) => + section.items.map((item) => ({ ...item, sectionId: section.id })), + ); + const dbItems = dbBoard.sections.flatMap((section) => + section.items.map((item) => ({ ...item, sectionId: section.id })), ); - } - const removedItems = filterRemovedItems(inputItems, dbItems); + const addedItems = filterAddedItems(inputItems, dbItems); - const itemIds = removedItems.map((item) => item.id); - if (itemIds.length > 0) { - await transaction.delete(items).where(inArray(items.id, itemIds)); - } + if (addedItems.length > 0) { + await transaction.insert(schema.items).values( + addedItems.map((item) => ({ + id: item.id, + kind: item.kind, + height: item.height, + width: item.width, + xOffset: item.xOffset, + yOffset: item.yOffset, + options: superjson.stringify(item.options), + advancedOptions: superjson.stringify(item.advancedOptions), + sectionId: item.sectionId, + })), + ); + } - const removedSections = filterRemovedItems(input.sections, dbBoard.sections); - const sectionIds = removedSections.map((section) => section.id); + const inputIntegrationRelations = inputItems.flatMap(({ integrationIds, id: itemId }) => + integrationIds.map((integrationId) => ({ + integrationId, + itemId, + })), + ); + const dbIntegrationRelations = dbItems.flatMap(({ integrationIds, id: itemId }) => + integrationIds.map((integrationId) => ({ + integrationId, + itemId, + })), + ); + const addedIntegrationRelations = inputIntegrationRelations.filter( + (inputRelation) => + !dbIntegrationRelations.some( + (dbRelation) => + dbRelation.itemId === inputRelation.itemId && + dbRelation.integrationId === inputRelation.integrationId, + ), + ); - if (sectionIds.length > 0) { - await transaction.delete(sections).where(inArray(sections.id, sectionIds)); - } + if (addedIntegrationRelations.length > 0) { + await transaction.insert(schema.integrationItems).values( + addedIntegrationRelations.map((relation) => ({ + itemId: relation.itemId, + integrationId: relation.integrationId, + })), + ); + } + + const updatedItems = filterUpdatedItems(inputItems, dbItems); + + for (const item of updatedItems) { + await transaction + .update(schema.items) + .set({ + kind: item.kind, + height: item.height, + width: item.width, + xOffset: item.xOffset, + yOffset: item.yOffset, + options: superjson.stringify(item.options), + advancedOptions: superjson.stringify(item.advancedOptions), + sectionId: item.sectionId, + }) + .where(eq(items.id, item.id)); + } + + const updatedSections = filterUpdatedItems(input.sections, dbBoard.sections); + + for (const section of updatedSections) { + const prev = dbBoard.sections.find((dbSection) => dbSection.id === section.id); + await transaction + .update(schema.sections) + .set({ + yOffset: section.yOffset, + xOffset: section.xOffset, + height: prev?.kind === "dynamic" && "height" in section ? section.height : null, + width: prev?.kind === "dynamic" && "width" in section ? section.width : null, + parentSectionId: + prev?.kind === "dynamic" && "parentSectionId" in section ? section.parentSectionId : null, + name: prev?.kind === "category" && "name" in section ? section.name : null, + }) + .where(eq(sections.id, section.id)); + } + + const removedIntegrationRelations = dbIntegrationRelations.filter( + (dbRelation) => + !inputIntegrationRelations.some( + (inputRelation) => + dbRelation.itemId === inputRelation.itemId && + dbRelation.integrationId === inputRelation.integrationId, + ), + ); + + for (const relation of removedIntegrationRelations) { + await transaction + .delete(schema.integrationItems) + .where( + and( + eq(integrationItems.itemId, relation.itemId), + eq(integrationItems.integrationId, relation.integrationId), + ), + ); + } + + const removedItems = filterRemovedItems(inputItems, dbItems); + + const itemIds = removedItems.map((item) => item.id); + if (itemIds.length > 0) { + await transaction.delete(schema.items).where(inArray(items.id, itemIds)); + } + + const removedSections = filterRemovedItems(input.sections, dbBoard.sections); + const sectionIds = removedSections.map((section) => section.id); + + if (sectionIds.length > 0) { + await transaction.delete(schema.sections).where(inArray(sections.id, sectionIds)); + } + }); + }, + handleSync(db) { + db.transaction((transaction) => { + const addedSections = filterAddedItems(input.sections, dbBoard.sections); + + if (addedSections.length > 0) { + transaction + .insert(sections) + .values( + addedSections.map((section) => ({ + id: section.id, + kind: section.kind, + yOffset: section.yOffset, + xOffset: section.kind === "dynamic" ? section.xOffset : 0, + height: "height" in section ? section.height : null, + width: "width" in section ? section.width : null, + parentSectionId: "parentSectionId" in section ? section.parentSectionId : null, + name: "name" in section ? section.name : null, + boardId: dbBoard.id, + })), + ) + .run(); + } + + const inputItems = input.sections.flatMap((section) => + section.items.map((item) => ({ ...item, sectionId: section.id })), + ); + const dbItems = dbBoard.sections.flatMap((section) => + section.items.map((item) => ({ ...item, sectionId: section.id })), + ); + + const addedItems = filterAddedItems(inputItems, dbItems); + + if (addedItems.length > 0) { + transaction + .insert(items) + .values( + addedItems.map((item) => ({ + id: item.id, + kind: item.kind, + height: item.height, + width: item.width, + xOffset: item.xOffset, + yOffset: item.yOffset, + options: superjson.stringify(item.options), + advancedOptions: superjson.stringify(item.advancedOptions), + sectionId: item.sectionId, + })), + ) + .run(); + } + + const inputIntegrationRelations = inputItems.flatMap(({ integrationIds, id: itemId }) => + integrationIds.map((integrationId) => ({ + integrationId, + itemId, + })), + ); + const dbIntegrationRelations = dbItems.flatMap(({ integrationIds, id: itemId }) => + integrationIds.map((integrationId) => ({ + integrationId, + itemId, + })), + ); + const addedIntegrationRelations = inputIntegrationRelations.filter( + (inputRelation) => + !dbIntegrationRelations.some( + (dbRelation) => + dbRelation.itemId === inputRelation.itemId && + dbRelation.integrationId === inputRelation.integrationId, + ), + ); + + if (addedIntegrationRelations.length > 0) { + transaction + .insert(integrationItems) + .values( + addedIntegrationRelations.map((relation) => ({ + itemId: relation.itemId, + integrationId: relation.integrationId, + })), + ) + .run(); + } + + const updatedItems = filterUpdatedItems(inputItems, dbItems); + + for (const item of updatedItems) { + transaction + .update(items) + .set({ + kind: item.kind, + height: item.height, + width: item.width, + xOffset: item.xOffset, + yOffset: item.yOffset, + options: superjson.stringify(item.options), + advancedOptions: superjson.stringify(item.advancedOptions), + sectionId: item.sectionId, + }) + .where(eq(items.id, item.id)) + .run(); + } + + const updatedSections = filterUpdatedItems(input.sections, dbBoard.sections); + + for (const section of updatedSections) { + const prev = dbBoard.sections.find((dbSection) => dbSection.id === section.id); + transaction + .update(sections) + .set({ + yOffset: section.yOffset, + xOffset: section.xOffset, + height: prev?.kind === "dynamic" && "height" in section ? section.height : null, + width: prev?.kind === "dynamic" && "width" in section ? section.width : null, + parentSectionId: + prev?.kind === "dynamic" && "parentSectionId" in section ? section.parentSectionId : null, + name: prev?.kind === "category" && "name" in section ? section.name : null, + }) + .where(eq(sections.id, section.id)) + .run(); + } + + const removedIntegrationRelations = dbIntegrationRelations.filter( + (dbRelation) => + !inputIntegrationRelations.some( + (inputRelation) => + dbRelation.itemId === inputRelation.itemId && + dbRelation.integrationId === inputRelation.integrationId, + ), + ); + + for (const relation of removedIntegrationRelations) { + transaction + .delete(integrationItems) + .where( + and( + eq(integrationItems.itemId, relation.itemId), + eq(integrationItems.integrationId, relation.integrationId), + ), + ) + .run(); + } + + const removedItems = filterRemovedItems(inputItems, dbItems); + + const itemIds = removedItems.map((item) => item.id); + if (itemIds.length > 0) { + transaction.delete(items).where(inArray(items.id, itemIds)).run(); + } + + const removedSections = filterRemovedItems(input.sections, dbBoard.sections); + const sectionIds = removedSections.map((section) => section.id); + + if (sectionIds.length > 0) { + transaction.delete(sections).where(inArray(sections.id, sectionIds)).run(); + } + }); + }, }); }), @@ -542,18 +874,42 @@ export const boardRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.entityId), "full"); - await ctx.db.transaction(async (transaction) => { - await transaction.delete(boardUserPermissions).where(eq(boardUserPermissions.boardId, input.entityId)); - if (input.permissions.length === 0) { - return; - } - await transaction.insert(boardUserPermissions).values( - input.permissions.map((permission) => ({ - userId: permission.principalId, - permission: permission.permission, - boardId: input.entityId, - })), - ); + await handleTransactionsAsync(ctx.db, { + async handleAsync(db, schema) { + await db.transaction(async (transaction) => { + await transaction + .delete(schema.boardUserPermissions) + .where(eq(boardUserPermissions.boardId, input.entityId)); + if (input.permissions.length === 0) { + return; + } + await transaction.insert(schema.boardUserPermissions).values( + input.permissions.map((permission) => ({ + userId: permission.principalId, + permission: permission.permission, + boardId: input.entityId, + })), + ); + }); + }, + handleSync(db) { + db.transaction((transaction) => { + transaction.delete(boardUserPermissions).where(eq(boardUserPermissions.boardId, input.entityId)).run(); + if (input.permissions.length === 0) { + return; + } + transaction + .insert(boardUserPermissions) + .values( + input.permissions.map((permission) => ({ + userId: permission.principalId, + permission: permission.permission, + boardId: input.entityId, + })), + ) + .run(); + }); + }, }); }), saveGroupBoardPermissions: protectedProcedure @@ -561,29 +917,77 @@ export const boardRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.entityId), "full"); - await ctx.db.transaction(async (transaction) => { - await transaction.delete(boardGroupPermissions).where(eq(boardGroupPermissions.boardId, input.entityId)); - if (input.permissions.length === 0) { - return; - } - await transaction.insert(boardGroupPermissions).values( - input.permissions.map((permission) => ({ - groupId: permission.principalId, - permission: permission.permission, - boardId: input.entityId, - })), - ); + await handleTransactionsAsync(ctx.db, { + async handleAsync(db, schema) { + await db.transaction(async (transaction) => { + await transaction + .delete(schema.boardGroupPermissions) + .where(eq(boardGroupPermissions.boardId, input.entityId)); + if (input.permissions.length === 0) { + return; + } + await transaction.insert(schema.boardGroupPermissions).values( + input.permissions.map((permission) => ({ + groupId: permission.principalId, + permission: permission.permission, + boardId: input.entityId, + })), + ); + }); + }, + handleSync(db) { + db.transaction((transaction) => { + transaction.delete(boardGroupPermissions).where(eq(boardGroupPermissions.boardId, input.entityId)).run(); + if (input.permissions.length === 0) { + return; + } + transaction + .insert(boardGroupPermissions) + .values( + input.permissions.map((permission) => ({ + groupId: permission.principalId, + permission: permission.permission, + boardId: input.entityId, + })), + ) + .run(); + }); + }, }); }), - importOldmarrConfig: protectedProcedure - .input(validation.board.importOldmarrConfig) + importOldmarrConfig: permissionRequiredProcedure + .requiresPermission("board-create") + .input(importJsonFileSchema) .mutation(async ({ input, ctx }) => { const content = await input.file.text(); const oldmarr = oldmarrConfigSchema.parse(JSON.parse(content)); - await importAsync(ctx.db, oldmarr, input.configuration); + await importOldmarrAsync(ctx.db, oldmarr, input.configuration); }), }); +/** + * Get the home board id of the user with the given device type + * For an example of a user with deviceType = 'mobile' it would go through the following order: + * 1. user.mobileHomeBoardId + * 2. user.homeBoardId + * 3. serverSettings.mobileHomeBoardId + * 4. serverSettings.homeBoardId + * 5. show NOT_FOUND error + */ +const getHomeIdBoardAsync = async ( + db: Database, + user: InferSelectModel | null, + deviceType: DeviceType, +) => { + const settingKey = deviceType === "mobile" ? "mobileHomeBoardId" : "homeBoardId"; + if (user?.[settingKey] || user?.homeBoardId) { + return user[settingKey] ?? user.homeBoardId; + } else { + const boardSettings = await getServerSettingByKeyAsync(db, "board"); + return boardSettings[settingKey] ?? boardSettings.homeBoardId; + } +}; + const noBoardWithSimilarNameAsync = async (db: Database, name: string, ignoredIds: string[] = []) => { const boards = await db.query.boards.findMany({ columns: { diff --git a/packages/api/src/router/board/board-access.ts b/packages/api/src/router/board/board-access.ts index 0bce8817a..1e4351cba 100644 --- a/packages/api/src/router/board/board-access.ts +++ b/packages/api/src/router/board/board-access.ts @@ -4,7 +4,7 @@ import type { Session } from "@homarr/auth"; import { constructBoardPermissions } from "@homarr/auth/shared"; import type { Database, SQL } from "@homarr/db"; import { eq, inArray } from "@homarr/db"; -import { boardGroupPermissions, boardUserPermissions, groupMembers } from "@homarr/db/schema/sqlite"; +import { boardGroupPermissions, boardUserPermissions, groupMembers } from "@homarr/db/schema"; import type { BoardPermission } from "@homarr/definitions"; /** diff --git a/packages/api/src/router/certificates/certificate-router.ts b/packages/api/src/router/certificates/certificate-router.ts new file mode 100644 index 000000000..d50150c80 --- /dev/null +++ b/packages/api/src/router/certificates/certificate-router.ts @@ -0,0 +1,27 @@ +import { z } from "zod"; +import { zfd } from "zod-form-data"; + +import { addCustomRootCertificateAsync, removeCustomRootCertificateAsync } from "@homarr/certificates/server"; +import { superRefineCertificateFile, validation } from "@homarr/validation"; + +import { createTRPCRouter, permissionRequiredProcedure } from "../../trpc"; + +export const certificateRouter = createTRPCRouter({ + addCertificate: permissionRequiredProcedure + .requiresPermission("admin") + .input( + zfd.formData({ + file: zfd.file().superRefine(superRefineCertificateFile), + }), + ) + .mutation(async ({ input }) => { + const content = await input.file.text(); + await addCustomRootCertificateAsync(input.file.name, content); + }), + removeCertificate: permissionRequiredProcedure + .requiresPermission("admin") + .input(z.object({ fileName: validation.certificates.validFileNameSchema })) + .mutation(async ({ input }) => { + await removeCustomRootCertificateAsync(input.fileName); + }), +}); diff --git a/packages/api/src/router/docker/docker-router.ts b/packages/api/src/router/docker/docker-router.ts index 127573173..6a8b99a1f 100644 --- a/packages/api/src/router/docker/docker-router.ts +++ b/packages/api/src/router/docker/docker-router.ts @@ -3,8 +3,9 @@ import type Docker from "dockerode"; import type { Container } from "dockerode"; import { db, like, or } from "@homarr/db"; -import { icons } from "@homarr/db/schema/sqlite"; +import { icons } from "@homarr/db/schema"; import type { DockerContainerState } from "@homarr/definitions"; +import { logger } from "@homarr/log"; import { createCacheChannel } from "@homarr/redis"; import { z } from "@homarr/validation"; @@ -17,42 +18,60 @@ const dockerCache = createCacheChannel<{ export const dockerRouter = createTRPCRouter({ getContainers: permissionRequiredProcedure.requiresPermission("admin").query(async () => { - const { timestamp, data } = await dockerCache.consumeAsync(async () => { - const dockerInstances = DockerSingleton.getInstance(); - const containers = await Promise.all( - // Return all the containers of all the instances into only one item - dockerInstances.map(({ instance, host: key }) => - instance.listContainers({ all: true }).then((containers) => - containers.map((container) => ({ - ...container, - instance: key, - })), + const result = await dockerCache + .consumeAsync(async () => { + const dockerInstances = DockerSingleton.getInstance(); + const containers = await Promise.all( + // Return all the containers of all the instances into only one item + dockerInstances.map(({ instance, host: key }) => + instance.listContainers({ all: true }).then((containers) => + containers.map((container) => ({ + ...container, + instance: key, + })), + ), ), - ), - ).then((containers) => containers.flat()); + ).then((containers) => containers.flat()); - const extractImage = (container: Docker.ContainerInfo) => - container.Image.split("/").at(-1)?.split(":").at(0) ?? ""; - const likeQueries = containers.map((container) => like(icons.name, `%${extractImage(container)}%`)); - const dbIcons = - likeQueries.length >= 1 - ? await db.query.icons.findMany({ - where: or(...likeQueries), - }) - : []; + const extractImage = (container: Docker.ContainerInfo) => + container.Image.split("/").at(-1)?.split(":").at(0) ?? ""; + const likeQueries = containers.map((container) => like(icons.name, `%${extractImage(container)}%`)); + const dbIcons = + likeQueries.length >= 1 + ? await db.query.icons.findMany({ + where: or(...likeQueries), + }) + : []; - return { - containers: containers.map((container) => ({ - ...container, - iconUrl: - dbIcons.find((icon) => { - const extractedImage = extractImage(container); - if (!extractedImage) return false; - return icon.name.toLowerCase().includes(extractedImage.toLowerCase()); - })?.url ?? null, - })), - }; - }); + return { + containers: containers.map((container) => ({ + ...container, + iconUrl: + dbIcons.find((icon) => { + const extractedImage = extractImage(container); + if (!extractedImage) return false; + return icon.name.toLowerCase().includes(extractedImage.toLowerCase()); + })?.url ?? null, + })), + }; + }) + .catch((error) => { + logger.error(error); + return { + isError: true, + error: error as unknown, + }; + }); + + if ("isError" in result) { + throw new TRPCError({ + code: "INTERNAL_SERVER_ERROR", + message: "An error occurred while fetching the containers", + cause: result.error, + }); + } + + const { data, timestamp } = result; return { containers: sanitizeContainers(data.containers), diff --git a/packages/api/src/router/group.ts b/packages/api/src/router/group.ts index 83a0f8868..a10629802 100644 --- a/packages/api/src/router/group.ts +++ b/packages/api/src/router/group.ts @@ -2,12 +2,13 @@ import { TRPCError } from "@trpc/server"; import type { Database } from "@homarr/db"; import { and, createId, eq, like, not, sql } from "@homarr/db"; -import { groupMembers, groupPermissions, groups } from "@homarr/db/schema/sqlite"; +import { groupMembers, groupPermissions, groups } from "@homarr/db/schema"; import { everyoneGroup } from "@homarr/definitions"; import { validation, z } from "@homarr/validation"; -import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure } from "../trpc"; +import { createTRPCRouter, onboardingProcedure, permissionRequiredProcedure, protectedProcedure } from "../trpc"; import { throwIfCredentialsDisabled } from "./invite/checks"; +import { nextOnboardingStepAsync } from "./onboard/onboard-queries"; export const groupRouter = createTRPCRouter({ getPaginated: permissionRequiredProcedure @@ -145,6 +146,25 @@ export const groupRouter = createTRPCRouter({ limit: input.limit, }); }), + createInitialExternalGroup: onboardingProcedure + .requiresStep("group") + .input(validation.group.create) + .mutation(async ({ input, ctx }) => { + await checkSimilarNameAndThrowAsync(ctx.db, input.name); + + const groupId = createId(); + await ctx.db.insert(groups).values({ + id: groupId, + name: input.name, + }); + + await ctx.db.insert(groupPermissions).values({ + groupId, + permission: "admin", + }); + + await nextOnboardingStepAsync(ctx.db, undefined); + }), createGroup: permissionRequiredProcedure .requiresPermission("admin") .input(validation.group.create) diff --git a/packages/api/src/router/home.ts b/packages/api/src/router/home.ts index 2174a2968..7b65c74f3 100644 --- a/packages/api/src/router/home.ts +++ b/packages/api/src/router/home.ts @@ -3,7 +3,7 @@ import type { AnySQLiteTable } from "drizzle-orm/sqlite-core"; import { isProviderEnabled } from "@homarr/auth/server"; import type { Database } from "@homarr/db"; import { count } from "@homarr/db"; -import { apps, boards, groups, integrations, invites, users } from "@homarr/db/schema/sqlite"; +import { apps, boards, groups, integrations, invites, users } from "@homarr/db/schema"; import { createTRPCRouter, publicProcedure } from "../trpc"; diff --git a/packages/api/src/router/icons.ts b/packages/api/src/router/icons.ts index 7b7c2f52b..9a273336d 100644 --- a/packages/api/src/router/icons.ts +++ b/packages/api/src/router/icons.ts @@ -1,5 +1,5 @@ -import { count, like } from "@homarr/db"; -import { icons } from "@homarr/db/schema/sqlite"; +import { and, count, like } from "@homarr/db"; +import { icons } from "@homarr/db/schema"; import { validation } from "@homarr/validation"; import { createTRPCRouter, publicProcedure } from "../trpc"; @@ -15,7 +15,11 @@ export const iconsRouter = createTRPCRouter({ name: true, url: true, }, - where: (input.searchText?.length ?? 0) > 0 ? like(icons.name, `%${input.searchText}%`) : undefined, + where: + (input.searchText?.length ?? 0) > 0 + ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + and(...input.searchText!.split(" ").map((keyword) => like(icons.name, `%${keyword}%`))) + : undefined, limit: input.limitPerGroup, }, }, diff --git a/packages/api/src/router/import/import-router.ts b/packages/api/src/router/import/import-router.ts new file mode 100644 index 000000000..7bcc453ec --- /dev/null +++ b/packages/api/src/router/import/import-router.ts @@ -0,0 +1,42 @@ +import { analyseOldmarrImportForRouterAsync, analyseOldmarrImportInputSchema } from "@homarr/old-import/analyse"; +import { + ensureValidTokenOrThrow, + importInitialOldmarrAsync, + importInitialOldmarrInputSchema, +} from "@homarr/old-import/import"; +import { z } from "@homarr/validation"; + +import { createTRPCRouter, onboardingProcedure } from "../../trpc"; +import { nextOnboardingStepAsync } from "../onboard/onboard-queries"; + +export const importRouter = createTRPCRouter({ + analyseInitialOldmarrImport: onboardingProcedure + .requiresStep("import") + .input(analyseOldmarrImportInputSchema) + .mutation(async ({ input }) => { + return await analyseOldmarrImportForRouterAsync(input); + }), + validateToken: onboardingProcedure + .requiresStep("import") + .input( + z.object({ + checksum: z.string(), + token: z.string(), + }), + ) + .mutation(({ input }) => { + try { + ensureValidTokenOrThrow(input.checksum, input.token); + return true; + } catch { + return false; + } + }), + importInitialOldmarrImport: onboardingProcedure + .requiresStep("import") + .input(importInitialOldmarrInputSchema) + .mutation(async ({ ctx, input }) => { + await importInitialOldmarrAsync(ctx.db, input); + await nextOnboardingStepAsync(ctx.db, undefined); + }), +}); diff --git a/packages/api/src/router/integration/integration-access.ts b/packages/api/src/router/integration/integration-access.ts index f8e83e90b..78f8961e4 100644 --- a/packages/api/src/router/integration/integration-access.ts +++ b/packages/api/src/router/integration/integration-access.ts @@ -4,7 +4,7 @@ import type { Session } from "@homarr/auth"; import { constructIntegrationPermissions } from "@homarr/auth/shared"; import type { Database, SQL } from "@homarr/db"; import { eq, inArray } from "@homarr/db"; -import { groupMembers, integrationGroupPermissions, integrationUserPermissions } from "@homarr/db/schema/sqlite"; +import { groupMembers, integrationGroupPermissions, integrationUserPermissions } from "@homarr/db/schema"; import type { IntegrationPermission } from "@homarr/definitions"; /** diff --git a/packages/api/src/router/integration/integration-router.ts b/packages/api/src/router/integration/integration-router.ts index 54963407e..4ad169bf8 100644 --- a/packages/api/src/router/integration/integration-router.ts +++ b/packages/api/src/router/integration/integration-router.ts @@ -3,7 +3,7 @@ import { TRPCError } from "@trpc/server"; import { objectEntries } from "@homarr/common"; import { decryptSecret, encryptSecret } from "@homarr/common/server"; import type { Database } from "@homarr/db"; -import { and, asc, createId, eq, inArray, like } from "@homarr/db"; +import { and, asc, createId, eq, handleTransactionsAsync, inArray, like } from "@homarr/db"; import { groupMembers, groupPermissions, @@ -11,18 +11,21 @@ import { integrations, integrationSecrets, integrationUserPermissions, -} from "@homarr/db/schema/sqlite"; + searchEngines, +} from "@homarr/db/schema"; import type { IntegrationSecretKind } from "@homarr/definitions"; import { + getIconUrl, + getIntegrationKindsByCategory, getPermissionsWithParents, integrationDefs, integrationKinds, integrationSecretKindObject, - isIntegrationWithSearchSupport, } from "@homarr/definitions"; -import { integrationCreatorFromSecrets } from "@homarr/integrations"; +import { integrationCreator } from "@homarr/integrations"; import { validation, z } from "@homarr/validation"; +import { createOneIntegrationMiddleware } from "../../middlewares/integration"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../../trpc"; import { throwIfActionForbiddenAsync } from "./integration-access"; import { testConnectionAsync } from "./integration-test-connection"; @@ -90,7 +93,7 @@ export const integrationRouter = createTRPCRouter({ where: inArray( integrations.kind, objectEntries(integrationDefs) - .filter(([_, integration]) => integration.supportsSearch) + .filter(([_, integration]) => [...integration.category].includes("search")) .map(([kind, _]) => kind), ), }); @@ -127,6 +130,16 @@ export const integrationRouter = createTRPCRouter({ limit: input.limit, }); }), + // This is used to get the integrations by their ids it's public because it's needed to get integrations data in the boards + byIds: publicProcedure.input(z.array(z.string())).query(async ({ ctx, input }) => { + return await ctx.db.query.integrations.findMany({ + where: inArray(integrations.id, input), + columns: { + id: true, + kind: true, + }, + }); + }), byId: protectedProcedure.input(validation.integration.byId).query(async ({ ctx, input }) => { await throwIfActionForbiddenAsync(ctx, eq(integrations.id, input.id), "full"); const integration = await ctx.db.query.integrations.findFirst({ @@ -191,6 +204,18 @@ export const integrationRouter = createTRPCRouter({ })), ); } + + if (input.attemptSearchEngineCreation) { + const icon = getIconUrl(input.kind); + await ctx.db.insert(searchEngines).values({ + id: createId(), + name: input.name, + integrationId, + type: "fromIntegration", + iconUrl: icon, + short: await getNextValidShortNameForSearchEngineAsync(ctx.db, input.name), + }); + } }), update: protectedProcedure.input(validation.integration.update).mutation(async ({ ctx, input }) => { await throwIfActionForbiddenAsync(ctx, eq(integrations.id, input.id), "full"); @@ -345,20 +370,45 @@ export const integrationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { await throwIfActionForbiddenAsync(ctx, eq(integrations.id, input.entityId), "full"); - await ctx.db.transaction(async (transaction) => { - await transaction - .delete(integrationUserPermissions) - .where(eq(integrationUserPermissions.integrationId, input.entityId)); - if (input.permissions.length === 0) { - return; - } - await transaction.insert(integrationUserPermissions).values( - input.permissions.map((permission) => ({ - userId: permission.principalId, - permission: permission.permission, - integrationId: input.entityId, - })), - ); + await handleTransactionsAsync(ctx.db, { + async handleAsync(db, schema) { + await ctx.db.transaction(async (transaction) => { + await transaction + .delete(schema.integrationUserPermissions) + .where(eq(schema.integrationUserPermissions.integrationId, input.entityId)); + if (input.permissions.length === 0) { + return; + } + await transaction.insert(schema.integrationUserPermissions).values( + input.permissions.map((permission) => ({ + userId: permission.principalId, + permission: permission.permission, + integrationId: input.entityId, + })), + ); + }); + }, + handleSync(db) { + db.transaction((transaction) => { + transaction + .delete(integrationUserPermissions) + .where(eq(integrationUserPermissions.integrationId, input.entityId)) + .run(); + if (input.permissions.length === 0) { + return; + } + transaction + .insert(integrationUserPermissions) + .values( + input.permissions.map((permission) => ({ + userId: permission.principalId, + permission: permission.permission, + integrationId: input.entityId, + })), + ) + .run(); + }); + }, }); }), saveGroupIntegrationPermissions: protectedProcedure @@ -366,48 +416,53 @@ export const integrationRouter = createTRPCRouter({ .mutation(async ({ input, ctx }) => { await throwIfActionForbiddenAsync(ctx, eq(integrations.id, input.entityId), "full"); - await ctx.db.transaction(async (transaction) => { - await transaction - .delete(integrationGroupPermissions) - .where(eq(integrationGroupPermissions.integrationId, input.entityId)); - if (input.permissions.length === 0) { - return; - } - await transaction.insert(integrationGroupPermissions).values( - input.permissions.map((permission) => ({ - groupId: permission.principalId, - permission: permission.permission, - integrationId: input.entityId, - })), - ); + await handleTransactionsAsync(ctx.db, { + async handleAsync(db, schema) { + await db.transaction(async (transaction) => { + await transaction + .delete(schema.integrationGroupPermissions) + .where(eq(schema.integrationGroupPermissions.integrationId, input.entityId)); + if (input.permissions.length === 0) { + return; + } + await transaction.insert(schema.integrationGroupPermissions).values( + input.permissions.map((permission) => ({ + groupId: permission.principalId, + permission: permission.permission, + integrationId: input.entityId, + })), + ); + }); + }, + handleSync(db) { + db.transaction((transaction) => { + transaction + .delete(integrationGroupPermissions) + .where(eq(integrationGroupPermissions.integrationId, input.entityId)) + .run(); + if (input.permissions.length === 0) { + return; + } + transaction + .insert(integrationGroupPermissions) + .values( + input.permissions.map((permission) => ({ + groupId: permission.principalId, + permission: permission.permission, + integrationId: input.entityId, + })), + ) + .run(); + }); + }, }); }), searchInIntegration: protectedProcedure + .unstable_concat(createOneIntegrationMiddleware("query", ...getIntegrationKindsByCategory("search"))) .input(z.object({ integrationId: z.string(), query: z.string() })) .query(async ({ ctx, input }) => { - const integration = await ctx.db.query.integrations.findFirst({ - where: eq(integrations.id, input.integrationId), - with: { - secrets: true, - }, - }); - - if (!integration) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "The requested integration does not exist", - }); - } - - if (!isIntegrationWithSearchSupport(integration)) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "The requested integration does not support searching", - }); - } - - const integrationInstance = integrationCreatorFromSecrets(integration); - return await integrationInstance.searchAsync(input.query); + const integrationInstance = integrationCreator(ctx.integration); + return await integrationInstance.searchAsync(encodeURI(input.query)); }), }); @@ -430,6 +485,36 @@ interface AddSecretInput { value: string; kind: IntegrationSecretKind; } + +const getNextValidShortNameForSearchEngineAsync = async (db: Database, integrationName: string) => { + const searchEngines = await db.query.searchEngines.findMany({ + columns: { + short: true, + }, + }); + + const usedShortNames = searchEngines.flatMap((searchEngine) => searchEngine.short.toLowerCase()); + const nameByIntegrationName = integrationName.slice(0, 1).toLowerCase(); + + if (!usedShortNames.includes(nameByIntegrationName)) { + return nameByIntegrationName; + } + + // 8 is max length constraint + for (let i = 2; i < 9999999; i++) { + const generatedName = `${nameByIntegrationName}${i}`; + if (usedShortNames.includes(generatedName)) { + continue; + } + + return generatedName; + } + + throw new Error( + "Unable to automatically generate a short name. All possible variations were exhausted. Please disable the automatic creation and choose one later yourself.", + ); +}; + const addSecretAsync = async (db: Database, input: AddSecretInput) => { await db.insert(integrationSecrets).values({ kind: input.kind, diff --git a/packages/api/src/router/integration/integration-test-connection.ts b/packages/api/src/router/integration/integration-test-connection.ts index 93a0bc356..58fcc9d21 100644 --- a/packages/api/src/router/integration/integration-test-connection.ts +++ b/packages/api/src/router/integration/integration-test-connection.ts @@ -1,5 +1,5 @@ import { decryptSecret } from "@homarr/common/server"; -import type { Integration } from "@homarr/db/schema/sqlite"; +import type { Integration } from "@homarr/db/schema"; import type { IntegrationKind, IntegrationSecretKind } from "@homarr/definitions"; import { getAllSecretKindOptions } from "@homarr/definitions"; import { integrationCreator, IntegrationTestConnectionError } from "@homarr/integrations"; diff --git a/packages/api/src/router/invite.ts b/packages/api/src/router/invite.ts index 8599555d3..6cbcc2869 100644 --- a/packages/api/src/router/invite.ts +++ b/packages/api/src/router/invite.ts @@ -2,15 +2,16 @@ import { randomBytes } from "crypto"; import { TRPCError } from "@trpc/server"; import { asc, createId, eq } from "@homarr/db"; -import { invites } from "@homarr/db/schema/sqlite"; +import { invites } from "@homarr/db/schema"; import { selectInviteSchema } from "@homarr/db/validationSchemas"; import { z } from "@homarr/validation"; -import { createTRPCRouter, protectedProcedure } from "../trpc"; +import { createTRPCRouter, permissionRequiredProcedure } from "../trpc"; import { throwIfCredentialsDisabled } from "./invite/checks"; export const inviteRouter = createTRPCRouter({ - getAll: protectedProcedure + getAll: permissionRequiredProcedure + .requiresPermission("admin") .output( z.array( selectInviteSchema @@ -40,7 +41,8 @@ export const inviteRouter = createTRPCRouter({ }, }); }), - createInvite: protectedProcedure + createInvite: permissionRequiredProcedure + .requiresPermission("admin") .input( z.object({ expirationDate: z.date(), @@ -65,7 +67,8 @@ export const inviteRouter = createTRPCRouter({ token, }; }), - deleteInvite: protectedProcedure + deleteInvite: permissionRequiredProcedure + .requiresPermission("admin") .input( z.object({ id: z.string(), diff --git a/packages/api/src/router/invite/checks.ts b/packages/api/src/router/invite/checks.ts index 330faaae3..10585d8b2 100644 --- a/packages/api/src/router/invite/checks.ts +++ b/packages/api/src/router/invite/checks.ts @@ -1,6 +1,6 @@ import { TRPCError } from "@trpc/server"; -import { env } from "@homarr/auth/env.mjs"; +import { env } from "@homarr/auth/env"; export const throwIfCredentialsDisabled = () => { if (!env.AUTH_PROVIDERS.includes("credentials")) { diff --git a/packages/api/src/router/medias/media-router.ts b/packages/api/src/router/medias/media-router.ts index 90f497523..8a1c3a71e 100644 --- a/packages/api/src/router/medias/media-router.ts +++ b/packages/api/src/router/medias/media-router.ts @@ -1,7 +1,9 @@ import { TRPCError } from "@trpc/server"; +import type { InferInsertModel } from "@homarr/db"; import { and, createId, desc, eq, like } from "@homarr/db"; -import { medias } from "@homarr/db/schema/sqlite"; +import { iconRepositories, icons, medias } from "@homarr/db/schema"; +import { createLocalImageUrl, LOCAL_ICON_REPOSITORY_SLUG, mapMediaToIcon } from "@homarr/icons/local"; import { validation, z } from "@homarr/validation"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure } from "../../trpc"; @@ -52,13 +54,29 @@ export const mediaRouter = createTRPCRouter({ .mutation(async ({ ctx, input }) => { const content = Buffer.from(await input.file.arrayBuffer()); const id = createId(); - await ctx.db.insert(medias).values({ + const media = { id, creatorId: ctx.session.user.id, content, size: input.file.size, contentType: input.file.type, name: input.file.name, + } satisfies InferInsertModel; + await ctx.db.insert(medias).values(media); + + const localIconRepository = await ctx.db.query.iconRepositories.findFirst({ + where: eq(iconRepositories.slug, LOCAL_ICON_REPOSITORY_SLUG), + }); + + if (!localIconRepository) return id; + + const icon = mapMediaToIcon(media); + await ctx.db.insert(icons).values({ + id: createId(), + checksum: icon.checksum, + name: icon.fileNameWithExtension, + url: icon.imageUrl, + iconRepositoryId: localIconRepository.id, }); return id; @@ -67,6 +85,7 @@ export const mediaRouter = createTRPCRouter({ const dbMedia = await ctx.db.query.medias.findFirst({ where: eq(medias.id, input.id), columns: { + id: true, creatorId: true, }, }); @@ -87,5 +106,6 @@ export const mediaRouter = createTRPCRouter({ } await ctx.db.delete(medias).where(eq(medias.id, input.id)); + await ctx.db.delete(icons).where(eq(icons.url, createLocalImageUrl(input.id))); }), }); diff --git a/packages/api/src/router/onboard/onboard-queries.ts b/packages/api/src/router/onboard/onboard-queries.ts new file mode 100644 index 000000000..15f205d8b --- /dev/null +++ b/packages/api/src/router/onboard/onboard-queries.ts @@ -0,0 +1,81 @@ +import { isProviderEnabled } from "@homarr/auth/server"; +import { objectEntries } from "@homarr/common"; +import type { MaybePromise } from "@homarr/common/types"; +import type { Database } from "@homarr/db"; +import { eq } from "@homarr/db"; +import { groups, onboarding } from "@homarr/db/schema"; +import type { OnboardingStep } from "@homarr/definitions"; +import { credentialsAdminGroup } from "@homarr/definitions"; + +export const nextOnboardingStepAsync = async (db: Database, preferredStep: OnboardingStep | undefined) => { + const { current } = await getOnboardingOrFallbackAsync(db); + const nextStepConfiguration = nextSteps[current]; + if (!nextStepConfiguration) return; + + for (const conditionalStep of objectEntries(nextStepConfiguration)) { + if (!conditionalStep) continue; + const [nextStep, condition] = conditionalStep; + if (condition === "preferred" && nextStep !== preferredStep) continue; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (typeof condition === "boolean" && !condition) continue; + if (typeof condition === "function" && !(await condition(db))) continue; + + await db.update(onboarding).set({ + previousStep: current, + step: nextStep, + }); + return; + } +}; + +export const getOnboardingOrFallbackAsync = async (db: Database) => { + const value = await db.query.onboarding.findFirst(); + if (!value) return { current: "start" as const, previous: null }; + + return { current: value.step, previous: value.previousStep }; +}; + +type NextStepCondition = true | "preferred" | ((db: Database) => MaybePromise); + +/** + * The below object is a definition of which can be the next step of the current one. + * If the value is `true`, it means the step can always be the next one. + * If the value is `preferred`, it means that the step can only be reached if the input `preferredStep` is set to the step. + * If the value is a function, it will be called with the database instance and should return a boolean. + * If the value or result is `false`, the step has to be skipped and the next value or callback should be checked. + */ +const nextSteps: Partial>>> = { + start: { + import: "preferred" as const, + user: () => isProviderEnabled("credentials"), + group: () => isProviderEnabled("ldap") || isProviderEnabled("oidc"), + settings: true, + }, + import: { + // eslint-disable-next-line no-restricted-syntax + user: async (db: Database) => { + if (!isProviderEnabled("credentials")) return false; + + const adminGroup = await db.query.groups.findFirst({ + where: eq(groups.name, credentialsAdminGroup), + with: { + members: true, + }, + }); + + return !adminGroup || adminGroup.members.length === 0; + }, + group: () => isProviderEnabled("ldap") || isProviderEnabled("oidc"), + settings: true, + }, + user: { + group: () => isProviderEnabled("ldap") || isProviderEnabled("oidc"), + settings: true, + }, + group: { + settings: true, + }, + settings: { + finish: true, + }, +}; diff --git a/packages/api/src/router/onboard/onboard-router.ts b/packages/api/src/router/onboard/onboard-router.ts new file mode 100644 index 000000000..89b6fb66f --- /dev/null +++ b/packages/api/src/router/onboard/onboard-router.ts @@ -0,0 +1,34 @@ +import { onboarding } from "@homarr/db/schema"; +import { onboardingSteps } from "@homarr/definitions"; +import { z, zodEnumFromArray } from "@homarr/validation"; + +import { createTRPCRouter, publicProcedure } from "../../trpc"; +import { getOnboardingOrFallbackAsync, nextOnboardingStepAsync } from "./onboard-queries"; + +export const onboardRouter = createTRPCRouter({ + currentStep: publicProcedure.query(async ({ ctx }) => { + return await getOnboardingOrFallbackAsync(ctx.db); + }), + nextStep: publicProcedure + .input( + z.object({ + // Preferred step is only needed for 'preferred' conditions + preferredStep: zodEnumFromArray(onboardingSteps).optional(), + }), + ) + .mutation(async ({ ctx, input }) => { + await nextOnboardingStepAsync(ctx.db, input.preferredStep); + }), + previousStep: publicProcedure.mutation(async ({ ctx }) => { + const { previous } = await getOnboardingOrFallbackAsync(ctx.db); + + if (previous !== "start") { + return; + } + + await ctx.db.update(onboarding).set({ + previousStep: null, + step: "start", + }); + }), +}); diff --git a/packages/api/src/router/search-engine/search-engine-router.ts b/packages/api/src/router/search-engine/search-engine-router.ts index 63c7c3bda..49aab777c 100644 --- a/packages/api/src/router/search-engine/search-engine-router.ts +++ b/packages/api/src/router/search-engine/search-engine-router.ts @@ -1,10 +1,13 @@ import { TRPCError } from "@trpc/server"; -import { createId, eq, like, sql } from "@homarr/db"; -import { searchEngines } from "@homarr/db/schema/sqlite"; -import { validation } from "@homarr/validation"; +import { asc, createId, eq, like, sql } from "@homarr/db"; +import { getServerSettingByKeyAsync } from "@homarr/db/queries"; +import { searchEngines, users } from "@homarr/db/schema"; +import { integrationCreator } from "@homarr/integrations"; +import { validation, z } from "@homarr/validation"; -import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure } from "../../trpc"; +import { createOneIntegrationMiddleware } from "../../middlewares/integration"; +import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../../trpc"; export const searchEngineRouter = createTRPCRouter({ getPaginated: protectedProcedure.input(validation.common.paginated).query(async ({ input, ctx }) => { @@ -27,6 +30,21 @@ export const searchEngineRouter = createTRPCRouter({ totalCount: searchEngineCount[0]?.count ?? 0, }; }), + getSelectable: protectedProcedure + .input(z.object({ withIntegrations: z.boolean() }).default({ withIntegrations: true })) + .query(async ({ ctx, input }) => { + return await ctx.db.query.searchEngines + .findMany({ + orderBy: asc(searchEngines.name), + where: input.withIntegrations ? undefined : eq(searchEngines.type, "generic"), + columns: { + id: true, + name: true, + }, + }) + .then((engines) => engines.map((engine) => ({ value: engine.id, label: engine.name }))); + }), + byId: protectedProcedure.input(validation.common.byId).query(async ({ ctx, input }) => { const searchEngine = await ctx.db.query.searchEngines.findFirst({ where: eq(searchEngines.id, input.id), @@ -53,12 +71,83 @@ export const searchEngineRouter = createTRPCRouter({ urlTemplate: searchEngine.urlTemplate!, }; }), + getDefaultSearchEngine: publicProcedure.query(async ({ ctx }) => { + const userDefaultId = ctx.session?.user.id + ? ((await ctx.db.query.users + .findFirst({ + where: eq(users.id, ctx.session.user.id), + columns: { + defaultSearchEngineId: true, + }, + }) + .then((user) => user?.defaultSearchEngineId)) ?? null) + : null; + + if (userDefaultId) { + return await ctx.db.query.searchEngines.findFirst({ + where: eq(searchEngines.id, userDefaultId), + with: { + integration: { + columns: { + kind: true, + url: true, + id: true, + }, + }, + }, + }); + } + + const serverDefaultId = await getServerSettingByKeyAsync(ctx.db, "search").then( + (setting) => setting.defaultSearchEngineId, + ); + + if (serverDefaultId) { + return await ctx.db.query.searchEngines.findFirst({ + where: eq(searchEngines.id, serverDefaultId), + with: { + integration: { + columns: { + kind: true, + url: true, + id: true, + }, + }, + }, + }); + } + + return null; + }), search: protectedProcedure.input(validation.common.search).query(async ({ ctx, input }) => { return await ctx.db.query.searchEngines.findMany({ where: like(searchEngines.short, `${input.query.toLowerCase().trim()}%`), + with: { + integration: { + columns: { + kind: true, + url: true, + id: true, + }, + }, + }, limit: input.limit, }); }), + getMediaRequestOptions: protectedProcedure + .unstable_concat(createOneIntegrationMiddleware("query", "jellyseerr", "overseerr")) + .input(validation.common.mediaRequestOptions) + .query(async ({ ctx, input }) => { + const integration = integrationCreator(ctx.integration); + return await integration.getSeriesInformationAsync(input.mediaType, input.mediaId); + }), + requestMedia: protectedProcedure + .unstable_concat(createOneIntegrationMiddleware("interact", "jellyseerr", "overseerr")) + .input(validation.common.requestMedia) + .mutation(async ({ ctx, input }) => { + const integration = integrationCreator(ctx.integration); + return await integration.requestMediaAsync(input.mediaType, input.mediaId, input.seasons); + }), create: permissionRequiredProcedure .requiresPermission("search-engine-create") .input(validation.searchEngine.manage) diff --git a/packages/api/src/router/serverSettings.ts b/packages/api/src/router/serverSettings.ts index d1ac27b7a..2fdb000f2 100644 --- a/packages/api/src/router/serverSettings.ts +++ b/packages/api/src/router/serverSettings.ts @@ -1,18 +1,20 @@ import { getServerSettingByKeyAsync, getServerSettingsAsync, updateServerSettingByKeyAsync } from "@homarr/db/queries"; import type { ServerSettings } from "@homarr/server-settings"; import { defaultServerSettingsKeys } from "@homarr/server-settings"; -import { z } from "@homarr/validation"; +import { validation, z } from "@homarr/validation"; -import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc"; +import { createTRPCRouter, onboardingProcedure, permissionRequiredProcedure, publicProcedure } from "../trpc"; +import { nextOnboardingStepAsync } from "./onboard/onboard-queries"; export const serverSettingsRouter = createTRPCRouter({ getCulture: publicProcedure.query(async ({ ctx }) => { return await getServerSettingByKeyAsync(ctx.db, "culture"); }), - getAll: protectedProcedure.query(async ({ ctx }) => { + getAll: permissionRequiredProcedure.requiresPermission("admin").query(async ({ ctx }) => { return await getServerSettingsAsync(ctx.db); }), - saveSettings: protectedProcedure + saveSettings: permissionRequiredProcedure + .requiresPermission("admin") .input( z.object({ settingsKey: z.enum(defaultServerSettingsKeys), @@ -26,4 +28,12 @@ export const serverSettingsRouter = createTRPCRouter({ input.value as ServerSettings[keyof ServerSettings], ); }), + initSettings: onboardingProcedure + .requiresStep("settings") + .input(validation.settings.init) + .mutation(async ({ ctx, input }) => { + await updateServerSettingByKeyAsync(ctx.db, "analytics", input.analytics); + await updateServerSettingByKeyAsync(ctx.db, "crawlingAndIndexing", input.crawlingAndIndexing); + await nextOnboardingStepAsync(ctx.db, undefined); + }), }); diff --git a/packages/api/src/router/test/app.spec.ts b/packages/api/src/router/test/app.spec.ts index 0354ad74e..488a2ed8f 100644 --- a/packages/api/src/router/test/app.spec.ts +++ b/packages/api/src/router/test/app.spec.ts @@ -3,7 +3,7 @@ import { describe, expect, test, vi } from "vitest"; import type { Session } from "@homarr/auth"; import { createId } from "@homarr/db"; -import { apps } from "@homarr/db/schema/sqlite"; +import { apps } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import type { GroupPermissionKey } from "@homarr/definitions"; @@ -24,6 +24,7 @@ describe("all should return all apps", () => { const db = createDb(); const caller = appRouter.createCaller({ db, + deviceType: undefined, session: createDefaultSession(), }); @@ -55,6 +56,7 @@ describe("all should return all apps", () => { // Arrange const caller = appRouter.createCaller({ db: createDb(), + deviceType: undefined, session: null, }); @@ -72,6 +74,7 @@ describe("byId should return an app by id", () => { const db = createDb(); const caller = appRouter.createCaller({ db, + deviceType: undefined, session: null, }); vi.spyOn(appAccessControl, "canUserSeeAppAsync").mockReturnValue(Promise.resolve(true)); @@ -103,6 +106,7 @@ describe("byId should return an app by id", () => { const db = createDb(); const caller = appRouter.createCaller({ db, + deviceType: undefined, session: null, }); await db.insert(apps).values([ @@ -128,6 +132,7 @@ describe("byId should return an app by id", () => { const db = createDb(); const caller = appRouter.createCaller({ db, + deviceType: undefined, session: null, }); @@ -145,6 +150,7 @@ describe("create should create a new app with all arguments", () => { const db = createDb(); const caller = appRouter.createCaller({ db, + deviceType: undefined, session: createDefaultSession(["app-create"]), }); const input = { @@ -171,6 +177,7 @@ describe("create should create a new app with all arguments", () => { const db = createDb(); const caller = appRouter.createCaller({ db, + deviceType: undefined, session: createDefaultSession(["app-create"]), }); const input = { @@ -199,6 +206,7 @@ describe("update should update an app", () => { const db = createDb(); const caller = appRouter.createCaller({ db, + deviceType: undefined, session: createDefaultSession(["app-modify-all"]), }); @@ -237,6 +245,7 @@ describe("update should update an app", () => { const db = createDb(); const caller = appRouter.createCaller({ db, + deviceType: undefined, session: createDefaultSession(["app-modify-all"]), }); @@ -261,6 +270,7 @@ describe("delete should delete an app", () => { const db = createDb(); const caller = appRouter.createCaller({ db, + deviceType: undefined, session: createDefaultSession(["app-full-all"]), }); diff --git a/packages/api/src/router/test/board.spec.ts b/packages/api/src/router/test/board.spec.ts index c8a50ca25..b829bf6c3 100644 --- a/packages/api/src/router/test/board.spec.ts +++ b/packages/api/src/router/test/board.spec.ts @@ -17,7 +17,7 @@ import { sections, serverSettings, users, -} from "@homarr/db/schema/sqlite"; +} from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import type { BoardPermission, GroupPermissionKey } from "@homarr/definitions"; @@ -52,7 +52,7 @@ describe("getAllBoards should return all boards accessable to the current user", test("without session it should return only public boards", async () => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: null }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: null }); const user1 = await createRandomUserAsync(db); const user2 = await createRandomUserAsync(db); @@ -85,6 +85,7 @@ describe("getAllBoards should return all boards accessable to the current user", const db = createDb(); const caller = boardRouter.createCaller({ db, + deviceType: undefined, session: { user: { id: defaultCreatorId, @@ -124,7 +125,7 @@ describe("getAllBoards should return all boards accessable to the current user", test("with session user beeing creator it should return all private boards of them", async () => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const user1 = await createRandomUserAsync(db); const user2 = await createRandomUserAsync(db); @@ -168,6 +169,7 @@ describe("getAllBoards should return all boards accessable to the current user", const db = createDb(); const caller = boardRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); @@ -232,6 +234,7 @@ describe("getAllBoards should return all boards accessable to the current user", const db = createDb(); const caller = boardRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); @@ -290,7 +293,7 @@ describe("createBoard should create a new board", () => { permissions: ["board-create"] satisfies GroupPermissionKey[], }, }; - const caller = boardRouter.createCaller({ db, session }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session }); await db.insert(users).values({ id: defaultCreatorId, @@ -316,7 +319,7 @@ describe("createBoard should create a new board", () => { test("should throw error when user has no board-create permission", async () => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => await caller.createBoard({ name: "newBoard", columnCount: 12, isPublic: true }); @@ -330,7 +333,7 @@ describe("rename board should rename board", () => { test("should rename board", async () => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); await db.insert(users).values({ @@ -358,7 +361,7 @@ describe("rename board should rename board", () => { test("should throw error when similar board name exists", async () => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); await db.insert(users).values({ id: defaultCreatorId, @@ -385,7 +388,7 @@ describe("rename board should rename board", () => { test("should throw error when board not found", async () => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => await caller.renameBoard({ id: "nonExistentBoardId", name: "newName" }); @@ -401,7 +404,7 @@ describe("changeBoardVisibility should change board visibility", () => { async (visibility) => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); await db.insert(users).values({ @@ -436,7 +439,7 @@ describe("deleteBoard should delete board", () => { test("should delete board", async () => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); await db.insert(users).values({ @@ -463,7 +466,7 @@ describe("deleteBoard should delete board", () => { test("should throw error when board not found", async () => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => await caller.deleteBoard({ id: "nonExistentBoardId" }); @@ -478,7 +481,7 @@ describe("getHomeBoard should return home board", () => { // Arrange const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const fullBoardProps = await createFullBoardAsync(db, "home"); await db @@ -502,7 +505,7 @@ describe("getHomeBoard should return home board", () => { // Arrange const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const fullBoardProps = await createFullBoardAsync(db, "home"); await db.insert(serverSettings).values({ @@ -523,7 +526,7 @@ describe("getHomeBoard should return home board", () => { test("should throw error when home board not configured in serverSettings", async () => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); await createFullBoardAsync(db, "home"); // Act @@ -539,7 +542,7 @@ describe("getBoardByName should return board by name", () => { // Arrange const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const fullBoardProps = await createFullBoardAsync(db, name); @@ -557,7 +560,7 @@ describe("getBoardByName should return board by name", () => { it("should throw error when not present", async () => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); await createFullBoardAsync(db, "default"); // Act @@ -573,7 +576,7 @@ describe("savePartialBoardSettings should save general settings", () => { // Arrange const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const newPageTitle = "newPageTitle"; const newMetaTitle = "newMetaTitle"; @@ -633,7 +636,7 @@ describe("savePartialBoardSettings should save general settings", () => { it("should throw error when board not found", async () => { const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const actAsync = async () => await caller.savePartialBoardSettings({ @@ -652,7 +655,7 @@ describe("saveBoard should save full board", () => { it("should remove section when not present in input", async () => { const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const { boardId, sectionId } = await createFullBoardAsync(db, "default"); @@ -689,7 +692,7 @@ describe("saveBoard should save full board", () => { it("should remove item when not present in input", async () => { const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const { boardId, itemId, sectionId } = await createFullBoardAsync(db, "default"); @@ -744,7 +747,7 @@ describe("saveBoard should save full board", () => { it("should remove integration reference when not present in input", async () => { const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const anotherIntegration = { id: createId(), kind: "adGuardHome", @@ -814,7 +817,7 @@ describe("saveBoard should save full board", () => { async (partialSection) => { const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const { boardId, sectionId } = await createFullBoardAsync(db, "default"); @@ -867,7 +870,7 @@ describe("saveBoard should save full board", () => { it("should add item when present in input", async () => { const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const { boardId, sectionId } = await createFullBoardAsync(db, "default"); @@ -931,7 +934,7 @@ describe("saveBoard should save full board", () => { it("should add integration reference when present in input", async () => { const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const integration = { id: createId(), kind: "plex", @@ -998,7 +1001,7 @@ describe("saveBoard should save full board", () => { }); it("should update section when present in input", async () => { const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const { boardId, sectionId } = await createFullBoardAsync(db, "default"); const newSectionId = createId(); @@ -1056,7 +1059,7 @@ describe("saveBoard should save full board", () => { it("should update item when present in input", async () => { const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const { boardId, itemId, sectionId } = await createFullBoardAsync(db, "default"); @@ -1112,7 +1115,7 @@ describe("saveBoard should save full board", () => { }); it("should fail when board not found", async () => { const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const actAsync = async () => await caller.saveBoard({ @@ -1128,7 +1131,7 @@ describe("getBoardPermissions should return board permissions", () => { test("should return board permissions", async () => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const user1 = await createRandomUserAsync(db); @@ -1202,7 +1205,7 @@ describe("saveUserBoardPermissions should save user board permissions", () => { async (permission) => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); const user1 = await createRandomUserAsync(db); @@ -1244,7 +1247,7 @@ describe("saveGroupBoardPermissions should save group board permissions", () => async (permission) => { // Arrange const db = createDb(); - const caller = boardRouter.createCaller({ db, session: defaultSession }); + const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); const spy = vi.spyOn(boardAccess, "throwIfActionForbiddenAsync"); await db.insert(users).values({ diff --git a/packages/api/src/router/test/board/board-access.spec.ts b/packages/api/src/router/test/board/board-access.spec.ts index 599d08489..370a5bc51 100644 --- a/packages/api/src/router/test/board/board-access.spec.ts +++ b/packages/api/src/router/test/board/board-access.spec.ts @@ -2,7 +2,7 @@ import { describe, expect, test, vi } from "vitest"; import * as authShared from "@homarr/auth/shared"; import { createId, eq } from "@homarr/db"; -import { boards, users } from "@homarr/db/schema/sqlite"; +import { boards, users } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import { throwIfActionForbiddenAsync } from "../../board/board-access"; diff --git a/packages/api/src/router/test/docker/docker-router.spec.ts b/packages/api/src/router/test/docker/docker-router.spec.ts index f81313fe2..24e3793c4 100644 --- a/packages/api/src/router/test/docker/docker-router.spec.ts +++ b/packages/api/src/router/test/docker/docker-router.spec.ts @@ -52,6 +52,7 @@ describe("All procedures should only be accessible for users with admin permissi // Arrange const caller = dockerRouter.createCaller({ db: null as unknown as Database, + deviceType: undefined, session: createSessionWithPermissions("admin"), }); @@ -68,6 +69,7 @@ describe("All procedures should only be accessible for users with admin permissi ); const caller = dockerRouter.createCaller({ db: null as unknown as Database, + deviceType: undefined, session: createSessionWithPermissions(...groupPermissionsWithoutAdmin), }); @@ -81,6 +83,7 @@ describe("All procedures should only be accessible for users with admin permissi // Arrange const caller = dockerRouter.createCaller({ db: null as unknown as Database, + deviceType: undefined, session: null, }); diff --git a/packages/api/src/router/test/group.spec.ts b/packages/api/src/router/test/group.spec.ts index b552e3bbd..f4d879005 100644 --- a/packages/api/src/router/test/group.spec.ts +++ b/packages/api/src/router/test/group.spec.ts @@ -1,9 +1,9 @@ import { describe, expect, test, vi } from "vitest"; import type { Session } from "@homarr/auth"; -import * as env from "@homarr/auth/env.mjs"; +import * as env from "@homarr/auth/env"; import { createId, eq } from "@homarr/db"; -import { groupMembers, groupPermissions, groups, users } from "@homarr/db/schema/sqlite"; +import { groupMembers, groupPermissions, groups, users } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import type { GroupPermissionKey } from "@homarr/definitions"; @@ -37,7 +37,7 @@ describe("paginated should return a list of groups with pagination", () => { async (page, expectedCount) => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); await db.insert(groups).values( [1, 2, 3, 4, 5].map((number) => ({ @@ -60,7 +60,7 @@ describe("paginated should return a list of groups with pagination", () => { test("with 5 groups in database and pagesize set to 3 it should return total count 5", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); await db.insert(groups).values( [1, 2, 3, 4, 5].map((number) => ({ @@ -81,7 +81,7 @@ describe("paginated should return a list of groups with pagination", () => { test("groups should contain id, name, email and image of members", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const user = createDummyUser(); await db.insert(users).values(user); @@ -117,7 +117,7 @@ describe("paginated should return a list of groups with pagination", () => { async (query, expectedCount, firstKey) => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); await db.insert(groups).values( ["first", "second", "third", "forth", "fifth"].map((key, index) => ({ @@ -140,7 +140,7 @@ describe("paginated should return a list of groups with pagination", () => { test("without admin permissions it should throw unauthorized error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: defaultSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => await caller.getPaginated({}); @@ -154,7 +154,7 @@ describe("byId should return group by id including members and permissions", () test('should return group with id "1" with members and permissions', async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const user = createDummyUser(); const groupId = "1"; @@ -197,7 +197,7 @@ describe("byId should return group by id including members and permissions", () test("with group id 1 and group 2 in database it should throw NOT_FOUND error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); await db.insert(groups).values({ id: "2", @@ -214,7 +214,7 @@ describe("byId should return group by id including members and permissions", () test("without admin permissions it should throw unauthorized error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: defaultSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => await caller.getById({ id: "1" }); @@ -228,7 +228,7 @@ describe("create should create group in database", () => { test("with valid input (64 character name) and non existing name it should be successful", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const name = "a".repeat(64); await db.insert(users).values(defaultSession.user); @@ -252,7 +252,7 @@ describe("create should create group in database", () => { test("with more than 64 characters name it should fail while validation", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const longName = "a".repeat(65); // Act @@ -273,7 +273,7 @@ describe("create should create group in database", () => { ])("with similar name %s it should fail to create %s", async (similarName, nameToCreate) => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); await db.insert(groups).values({ id: createId(), @@ -290,7 +290,7 @@ describe("create should create group in database", () => { test("without admin permissions it should throw unauthorized error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: defaultSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => await caller.createGroup({ name: "test" }); @@ -307,7 +307,7 @@ describe("update should update name with value that is no duplicate", () => { ])("update should update name from %s to %s normalized", async (initialValue, updateValue, expectedValue) => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const groupId = createId(); await db.insert(groups).values([ @@ -340,7 +340,7 @@ describe("update should update name with value that is no duplicate", () => { ])("with similar name %s it should fail to update %s", async (updateValue, initialDuplicate) => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const groupId = createId(); await db.insert(groups).values([ @@ -368,7 +368,7 @@ describe("update should update name with value that is no duplicate", () => { test("with non existing id it should throw not found error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); await db.insert(groups).values({ id: createId(), @@ -389,7 +389,7 @@ describe("update should update name with value that is no duplicate", () => { test("without admin permissions it should throw unauthorized error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: defaultSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => @@ -407,7 +407,7 @@ describe("savePermissions should save permissions for group", () => { test("with existing group and permissions it should save permissions", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const groupId = createId(); await db.insert(groups).values({ @@ -437,7 +437,7 @@ describe("savePermissions should save permissions for group", () => { test("with non existing group it should throw not found error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); await db.insert(groups).values({ id: createId(), @@ -458,7 +458,7 @@ describe("savePermissions should save permissions for group", () => { test("without admin permissions it should throw unauthorized error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: defaultSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => @@ -476,7 +476,7 @@ describe("transferOwnership should transfer ownership of group", () => { test("with existing group and user it should transfer ownership", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const groupId = createId(); const newUserId = createId(); @@ -513,7 +513,7 @@ describe("transferOwnership should transfer ownership of group", () => { test("with non existing group it should throw not found error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); await db.insert(groups).values({ id: createId(), @@ -534,7 +534,7 @@ describe("transferOwnership should transfer ownership of group", () => { test("without admin permissions it should throw unauthorized error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: defaultSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => @@ -552,7 +552,7 @@ describe("deleteGroup should delete group", () => { test("with existing group it should delete group", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const groupId = createId(); await db.insert(groups).values([ @@ -581,7 +581,7 @@ describe("deleteGroup should delete group", () => { test("with non existing group it should throw not found error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); await db.insert(groups).values({ id: createId(), @@ -601,7 +601,7 @@ describe("deleteGroup should delete group", () => { test("without admin permissions it should throw unauthorized error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: defaultSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => @@ -620,7 +620,7 @@ describe("addMember should add member to group", () => { const db = createDb(); const spy = vi.spyOn(env, "env", "get"); spy.mockReturnValue({ AUTH_PROVIDERS: ["credentials"] } as never); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const groupId = createId(); const userId = createId(); @@ -658,7 +658,7 @@ describe("addMember should add member to group", () => { test("with non existing group it should throw not found error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); await db.insert(users).values({ id: createId(), @@ -679,7 +679,7 @@ describe("addMember should add member to group", () => { test("without admin permissions it should throw unauthorized error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: defaultSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => @@ -697,7 +697,7 @@ describe("addMember should add member to group", () => { const db = createDb(); const spy = vi.spyOn(env, "env", "get"); spy.mockReturnValue({ AUTH_PROVIDERS: ["ldap"] } as never); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const groupId = createId(); const userId = createId(); @@ -735,7 +735,7 @@ describe("removeMember should remove member from group", () => { const db = createDb(); const spy = vi.spyOn(env, "env", "get"); spy.mockReturnValue({ AUTH_PROVIDERS: ["credentials"] } as never); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const groupId = createId(); const userId = createId(); @@ -776,7 +776,7 @@ describe("removeMember should remove member from group", () => { test("with non existing group it should throw not found error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); await db.insert(users).values({ id: createId(), @@ -797,7 +797,7 @@ describe("removeMember should remove member from group", () => { test("without admin permissions it should throw unauthorized error", async () => { // Arrange const db = createDb(); - const caller = groupRouter.createCaller({ db, session: defaultSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); // Act const actAsync = async () => @@ -815,7 +815,7 @@ describe("removeMember should remove member from group", () => { const db = createDb(); const spy = vi.spyOn(env, "env", "get"); spy.mockReturnValue({ AUTH_PROVIDERS: ["ldap"] } as never); - const caller = groupRouter.createCaller({ db, session: adminSession }); + const caller = groupRouter.createCaller({ db, deviceType: undefined, session: adminSession }); const groupId = createId(); const userId = createId(); diff --git a/packages/api/src/router/test/integration/integration-access.spec.ts b/packages/api/src/router/test/integration/integration-access.spec.ts index 5013c015f..7251f1e9a 100644 --- a/packages/api/src/router/test/integration/integration-access.spec.ts +++ b/packages/api/src/router/test/integration/integration-access.spec.ts @@ -2,7 +2,7 @@ import { describe, expect, test, vi } from "vitest"; import * as authShared from "@homarr/auth/shared"; import { createId, eq } from "@homarr/db"; -import { integrations, users } from "@homarr/db/schema/sqlite"; +import { integrations, users } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import { throwIfActionForbiddenAsync } from "../../integration/integration-access"; diff --git a/packages/api/src/router/test/integration/integration-router.spec.ts b/packages/api/src/router/test/integration/integration-router.spec.ts index 52a23f3b6..2aaf75a2f 100644 --- a/packages/api/src/router/test/integration/integration-router.spec.ts +++ b/packages/api/src/router/test/integration/integration-router.spec.ts @@ -4,7 +4,7 @@ import { describe, expect, test, vi } from "vitest"; import type { Session } from "@homarr/auth"; import { encryptSecret } from "@homarr/common/server"; import { createId } from "@homarr/db"; -import { integrations, integrationSecrets } from "@homarr/db/schema/sqlite"; +import { integrations, integrationSecrets } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import type { GroupPermissionKey } from "@homarr/definitions"; @@ -33,6 +33,7 @@ describe("all should return all integrations", () => { const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(), }); @@ -63,6 +64,7 @@ describe("byId should return an integration by id", () => { const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(["integration-full-all"]), }); @@ -89,6 +91,7 @@ describe("byId should return an integration by id", () => { const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(["integration-full-all"]), }); @@ -100,6 +103,7 @@ describe("byId should return an integration by id", () => { const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(["integration-full-all"]), }); @@ -147,6 +151,7 @@ describe("byId should return an integration by id", () => { const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(["integration-interact-all"]), }); @@ -172,6 +177,7 @@ describe("create should create a new integration", () => { const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(["integration-create"]), }); const input = { @@ -179,6 +185,7 @@ describe("create should create a new integration", () => { kind: "jellyfin" as const, url: "http://jellyfin.local", secrets: [{ kind: "apiKey" as const, value: "1234567890" }], + attemptSearchEngineCreation: false, }; const fakeNow = new Date("2023-07-01T00:00:00Z"); @@ -201,11 +208,55 @@ describe("create should create a new integration", () => { expect(dbSecret!.updatedAt).toEqual(fakeNow); }); + test("with create integration access should create a new integration when creating search engine", async () => { + const db = createDb(); + const caller = integrationRouter.createCaller({ + db, + deviceType: undefined, + session: defaultSessionWithPermissions(["integration-create"]), + }); + const input = { + name: "Jellyseerr", + kind: "jellyseerr" as const, + url: "http://jellyseerr.local", + secrets: [{ kind: "apiKey" as const, value: "1234567890" }], + attemptSearchEngineCreation: true, + }; + + const fakeNow = new Date("2023-07-01T00:00:00Z"); + vi.useFakeTimers(); + vi.setSystemTime(fakeNow); + await caller.create(input); + vi.useRealTimers(); + + const dbIntegration = await db.query.integrations.findFirst(); + const dbSecret = await db.query.integrationSecrets.findFirst(); + const dbSearchEngine = await db.query.searchEngines.findFirst(); + expect(dbIntegration).toBeDefined(); + expect(dbIntegration!.name).toBe(input.name); + expect(dbIntegration!.kind).toBe(input.kind); + expect(dbIntegration!.url).toBe(input.url); + + expect(dbSecret!.integrationId).toBe(dbIntegration!.id); + expect(dbSecret).toBeDefined(); + expect(dbSecret!.kind).toBe(input.secrets[0]!.kind); + expect(dbSecret!.value).toMatch(/^[a-f0-9]+.[a-f0-9]+$/); + expect(dbSecret!.updatedAt).toEqual(fakeNow); + + expect(dbSearchEngine!.integrationId).toBe(dbIntegration!.id); + expect(dbSearchEngine!.short).toBe("j"); + expect(dbSearchEngine!.name).toBe(input.name); + expect(dbSearchEngine!.iconUrl).toBe( + "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/jellyseerr.png", + ); + }); + test("without create integration access should throw permission error", async () => { // Arrange const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(["integration-interact-all"]), }); const input = { @@ -213,6 +264,7 @@ describe("create should create a new integration", () => { kind: "jellyfin" as const, url: "http://jellyfin.local", secrets: [{ kind: "apiKey" as const, value: "1234567890" }], + attemptSearchEngineCreation: false, }; // Act @@ -228,6 +280,7 @@ describe("update should update an integration", () => { const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(["integration-full-all"]), }); @@ -302,6 +355,7 @@ describe("update should update an integration", () => { const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(["integration-full-all"]), }); @@ -320,6 +374,7 @@ describe("update should update an integration", () => { const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(["integration-interact-all"]), }); @@ -342,6 +397,7 @@ describe("delete should delete an integration", () => { const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(["integration-full-all"]), }); @@ -375,6 +431,7 @@ describe("delete should delete an integration", () => { const db = createDb(); const caller = integrationRouter.createCaller({ db, + deviceType: undefined, session: defaultSessionWithPermissions(["integration-interact-all"]), }); diff --git a/packages/api/src/router/test/invite.spec.ts b/packages/api/src/router/test/invite.spec.ts index 6be30f7a9..fce81edd4 100644 --- a/packages/api/src/router/test/invite.spec.ts +++ b/packages/api/src/router/test/invite.spec.ts @@ -3,7 +3,7 @@ import { describe, expect, test, vi } from "vitest"; import type { Session } from "@homarr/auth"; import { createId } from "@homarr/db"; -import { invites, users } from "@homarr/db/schema/sqlite"; +import { invites, users } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import { inviteRouter } from "../invite"; @@ -11,7 +11,7 @@ import { inviteRouter } from "../invite"; const defaultSession = { user: { id: createId(), - permissions: [], + permissions: ["admin"], colorScheme: "light", }, expires: new Date().toISOString(), @@ -24,7 +24,7 @@ vi.mock("@homarr/auth", async () => { }); // Mock the env module to return the credentials provider -vi.mock("@homarr/auth/env.mjs", () => { +vi.mock("@homarr/auth/env", () => { return { env: { AUTH_PROVIDERS: ["credentials"], @@ -38,6 +38,7 @@ describe("all should return all existing invites without sensitive informations" const db = createDb(); const caller = inviteRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); @@ -72,6 +73,7 @@ describe("all should return all existing invites without sensitive informations" const db = createDb(); const caller = inviteRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); @@ -111,6 +113,7 @@ describe("create should create a new invite expiring on the specified date with const db = createDb(); const caller = inviteRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); await db.insert(users).values({ @@ -142,6 +145,7 @@ describe("delete should remove invite by id", () => { const db = createDb(); const caller = inviteRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); @@ -179,6 +183,7 @@ describe("delete should remove invite by id", () => { const db = createDb(); const caller = inviteRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); diff --git a/packages/api/src/router/test/serverSettings.spec.ts b/packages/api/src/router/test/serverSettings.spec.ts index 4f08132be..f2d3d848c 100644 --- a/packages/api/src/router/test/serverSettings.spec.ts +++ b/packages/api/src/router/test/serverSettings.spec.ts @@ -3,7 +3,7 @@ import { describe, expect, test, vi } from "vitest"; import type { Session } from "@homarr/auth"; import { createId } from "@homarr/db"; -import { serverSettings } from "@homarr/db/schema/sqlite"; +import { serverSettings } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import { defaultServerSettings, defaultServerSettingsKeys } from "@homarr/server-settings"; @@ -15,7 +15,7 @@ vi.mock("@homarr/auth", () => ({ auth: () => ({}) as Session })); const defaultSession = { user: { id: createId(), - permissions: [], + permissions: ["admin"], colorScheme: "light", }, expires: new Date().toISOString(), @@ -26,6 +26,7 @@ describe("getAll server settings", () => { const db = createDb(); const caller = serverSettingsRouter.createCaller({ db, + deviceType: undefined, session: null, }); @@ -44,6 +45,7 @@ describe("getAll server settings", () => { const db = createDb(); const caller = serverSettingsRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); @@ -58,6 +60,7 @@ describe("saveSettings", () => { const db = createDb(); const caller = serverSettingsRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); diff --git a/packages/api/src/router/test/user.spec.ts b/packages/api/src/router/test/user.spec.ts index ce02a5bc6..fc5f5af13 100644 --- a/packages/api/src/router/test/user.spec.ts +++ b/packages/api/src/router/test/user.spec.ts @@ -1,10 +1,11 @@ import { describe, expect, it, test, vi } from "vitest"; import type { Session } from "@homarr/auth"; -import { createId, eq, schema } from "@homarr/db"; -import { users } from "@homarr/db/schema/sqlite"; +import type { Database } from "@homarr/db"; +import { createId, eq } from "@homarr/db"; +import { invites, onboarding, users } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; -import type { GroupPermissionKey } from "@homarr/definitions"; +import type { GroupPermissionKey, OnboardingStep } from "@homarr/definitions"; import { userRouter } from "../user"; @@ -27,7 +28,7 @@ vi.mock("@homarr/auth", async () => { }); // Mock the env module to return the credentials provider -vi.mock("@homarr/auth/env.mjs", () => { +vi.mock("@homarr/auth/env", () => { return { env: { AUTH_PROVIDERS: ["credentials"], @@ -36,33 +37,12 @@ vi.mock("@homarr/auth/env.mjs", () => { }); describe("initUser should initialize the first user", () => { - it("should throw an error if a user already exists", async () => { - const db = createDb(); - const caller = userRouter.createCaller({ - db, - session: null, - }); - - await db.insert(schema.users).values({ - id: "test", - name: "test", - password: "test", - }); - - const actAsync = async () => - await caller.initUser({ - username: "test", - password: "123ABCdef+/-", - confirmPassword: "123ABCdef+/-", - }); - - await expect(actAsync()).rejects.toThrow("User already exists"); - }); - it("should create a user if none exists", async () => { const db = createDb(); + await createOnboardingStepAsync(db, "user"); const caller = userRouter.createCaller({ db, + deviceType: undefined, session: null, }); @@ -83,8 +63,10 @@ describe("initUser should initialize the first user", () => { it("should not create a user if the password and confirmPassword do not match", async () => { const db = createDb(); + await createOnboardingStepAsync(db, "user"); const caller = userRouter.createCaller({ db, + deviceType: undefined, session: null, }); @@ -106,8 +88,10 @@ describe("initUser should initialize the first user", () => { ["abc123+/-"], // does not contain uppercase ])("should throw error that password requirements do not match for '%s' as password", async (password) => { const db = createDb(); + await createOnboardingStepAsync(db, "user"); const caller = userRouter.createCaller({ db, + deviceType: undefined, session: null, }); @@ -128,6 +112,7 @@ describe("register should create a user with valid invitation", () => { const db = createDb(); const caller = userRouter.createCaller({ db, + deviceType: undefined, session: null, }); @@ -140,7 +125,7 @@ describe("register should create a user with valid invitation", () => { await db.insert(users).values({ id: userId, }); - await db.insert(schema.invites).values({ + await db.insert(invites).values({ id: inviteId, token: inviteToken, creatorId: userId, @@ -183,6 +168,7 @@ describe("register should create a user with valid invitation", () => { const db = createDb(); const caller = userRouter.createCaller({ db, + deviceType: undefined, session: null, }); @@ -195,7 +181,7 @@ describe("register should create a user with valid invitation", () => { await db.insert(users).values({ id: userId, }); - await db.insert(schema.invites).values({ + await db.insert(invites).values({ id: inviteId, token: inviteToken, creatorId: userId, @@ -225,12 +211,13 @@ describe("editProfile shoud update user", () => { const db = createDb(); const caller = userRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); const emailVerified = new Date(2024, 0, 5); - await db.insert(schema.users).values({ + await db.insert(users).values({ id: defaultOwnerId, name: "TEST 1", email: "abc@gmail.com", @@ -245,7 +232,7 @@ describe("editProfile shoud update user", () => { }); // assert - const user = await db.select().from(schema.users).where(eq(schema.users.id, defaultOwnerId)); + const user = await db.select().from(users).where(eq(users.id, defaultOwnerId)); expect(user).toHaveLength(1); expect(user[0]).containSubset({ @@ -261,10 +248,11 @@ describe("editProfile shoud update user", () => { const db = createDb(); const caller = userRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); - await db.insert(schema.users).values({ + await db.insert(users).values({ id: defaultOwnerId, name: "TEST 1", email: "abc@gmail.com", @@ -279,7 +267,7 @@ describe("editProfile shoud update user", () => { }); // assert - const user = await db.select().from(schema.users).where(eq(schema.users.id, defaultOwnerId)); + const user = await db.select().from(users).where(eq(users.id, defaultOwnerId)); expect(user).toHaveLength(1); expect(user[0]).containSubset({ @@ -296,6 +284,7 @@ describe("delete should delete user", () => { const db = createDb(); const caller = userRouter.createCaller({ db, + deviceType: undefined, session: defaultSession, }); @@ -314,13 +303,20 @@ describe("delete should delete user", () => { }, ]; - await db.insert(schema.users).values(initialUsers); + await db.insert(users).values(initialUsers); await caller.delete({ userId: defaultOwnerId }); - const usersInDb = await db.select().from(schema.users); + const usersInDb = await db.select().from(users); expect(usersInDb).toHaveLength(2); expect(usersInDb[0]).containSubset(initialUsers[0]); expect(usersInDb[1]).containSubset(initialUsers[2]); }); }); + +const createOnboardingStepAsync = async (db: Database, step: OnboardingStep) => { + await db.insert(onboarding).values({ + id: createId(), + step, + }); +}; diff --git a/packages/api/src/router/test/widgets/app.spec.ts b/packages/api/src/router/test/widgets/app.spec.ts index a728f9a94..3aacd2f59 100644 --- a/packages/api/src/router/test/widgets/app.spec.ts +++ b/packages/api/src/router/test/widgets/app.spec.ts @@ -18,6 +18,7 @@ describe("ping should call sendPingRequestAsync with url and return result", () const db = createDb(); const caller = appRouter.createCaller({ db, + deviceType: undefined, session: null, }); spy.mockImplementation(() => Promise.resolve({ error: "error" })); @@ -37,6 +38,7 @@ describe("ping should call sendPingRequestAsync with url and return result", () const db = createDb(); const caller = appRouter.createCaller({ db, + deviceType: undefined, session: null, }); spy.mockImplementation(() => Promise.resolve({ statusCode: 200 })); diff --git a/packages/api/src/router/update-checker.ts b/packages/api/src/router/update-checker.ts new file mode 100644 index 000000000..4b36c3f93 --- /dev/null +++ b/packages/api/src/router/update-checker.ts @@ -0,0 +1,11 @@ +import { updateCheckerRequestHandler } from "@homarr/request-handler/update-checker"; + +import { createTRPCRouter, permissionRequiredProcedure } from "../trpc"; + +export const updateCheckerRouter = createTRPCRouter({ + getAvailableUpdates: permissionRequiredProcedure.requiresPermission("admin").query(async () => { + const handler = updateCheckerRequestHandler.handler({}); + const data = await handler.getCachedOrUpdatedDataAsync({}); + return data.data.availableUpdates; + }), +}); diff --git a/packages/api/src/router/user.ts b/packages/api/src/router/user.ts index ae3b8cd88..0309fae64 100644 --- a/packages/api/src/router/user.ts +++ b/packages/api/src/router/user.ts @@ -2,50 +2,50 @@ import { TRPCError } from "@trpc/server"; import { createSaltAsync, hashPasswordAsync } from "@homarr/auth"; import type { Database } from "@homarr/db"; -import { and, createId, eq, like, schema } from "@homarr/db"; -import { groupMembers, groupPermissions, groups, invites, users } from "@homarr/db/schema/sqlite"; +import { and, createId, eq, like } from "@homarr/db"; +import { boards, groupMembers, groupPermissions, groups, invites, users } from "@homarr/db/schema"; import { selectUserSchema } from "@homarr/db/validationSchemas"; +import { credentialsAdminGroup } from "@homarr/definitions"; import type { SupportedAuthProvider } from "@homarr/definitions"; import { logger } from "@homarr/log"; import { validation, z } from "@homarr/validation"; import { convertIntersectionToZodObject } from "../schema-merger"; -import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../trpc"; +import { + createTRPCRouter, + onboardingProcedure, + permissionRequiredProcedure, + protectedProcedure, + publicProcedure, +} from "../trpc"; +import { throwIfActionForbiddenAsync } from "./board/board-access"; import { throwIfCredentialsDisabled } from "./invite/checks"; +import { nextOnboardingStepAsync } from "./onboard/onboard-queries"; export const userRouter = createTRPCRouter({ - initUser: publicProcedure.input(validation.user.init).mutation(async ({ ctx, input }) => { - throwIfCredentialsDisabled(); + initUser: onboardingProcedure + .requiresStep("user") + .input(validation.user.init) + .mutation(async ({ ctx, input }) => { + throwIfCredentialsDisabled(); - const firstUser = await ctx.db.query.users.findFirst({ - columns: { - id: true, - }, - }); - - if (firstUser) { - throw new TRPCError({ - code: "FORBIDDEN", - message: "User already exists", + const userId = await createUserAsync(ctx.db, input); + const groupId = createId(); + await ctx.db.insert(groups).values({ + id: groupId, + name: credentialsAdminGroup, + ownerId: userId, }); - } - - const userId = await createUserAsync(ctx.db, input); - const groupId = createId(); - await ctx.db.insert(groups).values({ - id: groupId, - name: "admin", - ownerId: userId, - }); - await ctx.db.insert(groupPermissions).values({ - groupId, - permission: "admin", - }); - await ctx.db.insert(groupMembers).values({ - groupId, - userId, - }); - }), + await ctx.db.insert(groupPermissions).values({ + groupId, + permission: "admin", + }); + await ctx.db.insert(groupMembers).values({ + groupId, + userId, + }); + await nextOnboardingStepAsync(ctx.db, undefined); + }), register: publicProcedure .input(validation.user.registrationApi) .output(z.void()) @@ -210,8 +210,10 @@ export const userRouter = createTRPCRouter({ image: true, provider: true, homeBoardId: true, + mobileHomeBoardId: true, firstDayOfWeek: true, pingIconsEnabled: true, + defaultSearchEngineId: true, }), ) .meta({ openapi: { method: "GET", path: "/api/users/{userId}", tags: ["users"], protect: true } }) @@ -232,8 +234,10 @@ export const userRouter = createTRPCRouter({ image: true, provider: true, homeBoardId: true, + mobileHomeBoardId: true, firstDayOfWeek: true, pingIconsEnabled: true, + defaultSearchEngineId: true, }, where: eq(users.id, input.userId), }); @@ -372,8 +376,8 @@ export const userRouter = createTRPCRouter({ }) .where(eq(users.id, input.userId)); }), - changeHomeBoardId: protectedProcedure - .input(convertIntersectionToZodObject(validation.user.changeHomeBoard.and(z.object({ userId: z.string() })))) + changeHomeBoards: protectedProcedure + .input(convertIntersectionToZodObject(validation.user.changeHomeBoards.and(z.object({ userId: z.string() })))) .output(z.void()) .meta({ openapi: { method: "PATCH", path: "/api/users/changeHome", tags: ["users"], protect: true } }) .mutation(async ({ input, ctx }) => { @@ -400,10 +404,50 @@ export const userRouter = createTRPCRouter({ }); } + await throwIfActionForbiddenAsync(ctx, eq(boards.id, input.userId), "view"); + + await ctx.db + .update(users) + .set({ + homeBoardId: input.homeBoardId, + mobileHomeBoardId: input.mobileHomeBoardId, + }) + .where(eq(users.id, input.userId)); + }), + changeDefaultSearchEngine: protectedProcedure + .input( + convertIntersectionToZodObject(validation.user.changeDefaultSearchEngine.and(z.object({ userId: z.string() }))), + ) + .output(z.void()) + .meta({ openapi: { method: "PATCH", path: "/api/users/changeSearchEngine", tags: ["users"], protect: true } }) + .mutation(async ({ input, ctx }) => { + const user = ctx.session.user; + // Only admins can change other users passwords + if (!user.permissions.includes("admin") && user.id !== input.userId) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "User not found", + }); + } + + const dbUser = await ctx.db.query.users.findFirst({ + columns: { + id: true, + }, + where: eq(users.id, input.userId), + }); + + if (!dbUser) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "User not found", + }); + } + await ctx.db .update(users) .set({ - homeBoardId: input.homeBoardId, + defaultSearchEngineId: input.defaultSearchEngineId, }) .where(eq(users.id, input.userId)); }), @@ -510,7 +554,7 @@ const createUserAsync = async (db: Database, input: Omit { const client = integrationCreator(integration); @@ -75,7 +75,7 @@ export const dnsHoleRouter = createTRPCRouter({ }); }), - disable: publicProcedure + disable: protectedProcedure .input(controlsInputSchema) .unstable_concat(createOneIntegrationMiddleware("interact", ...getIntegrationKindsByCategory("dnsHole"))) .mutation(async ({ ctx: { integration }, input }) => { diff --git a/packages/api/src/router/widgets/downloads.ts b/packages/api/src/router/widgets/downloads.ts index e9cdb380e..db5fdd997 100644 --- a/packages/api/src/router/widgets/downloads.ts +++ b/packages/api/src/router/widgets/downloads.ts @@ -1,7 +1,7 @@ import { observable } from "@trpc/server/observable"; import type { Modify } from "@homarr/common/types"; -import type { Integration } from "@homarr/db/schema/sqlite"; +import type { Integration } from "@homarr/db/schema"; import type { IntegrationKindByCategory } from "@homarr/definitions"; import { getIntegrationKindsByCategory } from "@homarr/definitions"; import type { DownloadClientJobsAndStatus } from "@homarr/integrations"; diff --git a/packages/api/src/router/widgets/health-monitoring.ts b/packages/api/src/router/widgets/health-monitoring.ts index 2169efafd..a51cfed2e 100644 --- a/packages/api/src/router/widgets/health-monitoring.ts +++ b/packages/api/src/router/widgets/health-monitoring.ts @@ -1,15 +1,15 @@ import { observable } from "@trpc/server/observable"; -import { getIntegrationKindsByCategory } from "@homarr/definitions"; import type { HealthMonitoring } from "@homarr/integrations"; -import { systemInfoRequestHandler } from "@homarr/request-handler/health-monitoring"; +import type { ProxmoxClusterInfo } from "@homarr/integrations/types"; +import { clusterInfoRequestHandler, systemInfoRequestHandler } from "@homarr/request-handler/health-monitoring"; -import { createManyIntegrationMiddleware } from "../../middlewares/integration"; +import { createManyIntegrationMiddleware, createOneIntegrationMiddleware } from "../../middlewares/integration"; import { createTRPCRouter, publicProcedure } from "../../trpc"; export const healthMonitoringRouter = createTRPCRouter({ - getHealthStatus: publicProcedure - .unstable_concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("healthMonitoring"))) + getSystemHealthStatus: publicProcedure + .unstable_concat(createManyIntegrationMiddleware("query", "openmediavault", "dashDot")) .query(async ({ ctx }) => { return await Promise.all( ctx.integrations.map(async (integration) => { @@ -25,9 +25,8 @@ export const healthMonitoringRouter = createTRPCRouter({ }), ); }), - - subscribeHealthStatus: publicProcedure - .unstable_concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("healthMonitoring"))) + subscribeSystemHealthStatus: publicProcedure + .unstable_concat(createManyIntegrationMiddleware("query", "openmediavault", "dashDot")) .subscription(({ ctx }) => { return observable<{ integrationId: string; healthInfo: HealthMonitoring; timestamp: Date }>((emit) => { const unsubscribes: (() => void)[] = []; @@ -49,4 +48,26 @@ export const healthMonitoringRouter = createTRPCRouter({ }; }); }), + getClusterHealthStatus: publicProcedure + .unstable_concat(createOneIntegrationMiddleware("query", "proxmox")) + .query(async ({ ctx }) => { + const innerHandler = clusterInfoRequestHandler.handler(ctx.integration, {}); + const { data } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false }); + return data; + }), + subscribeClusterHealthStatus: publicProcedure + .unstable_concat(createOneIntegrationMiddleware("query", "proxmox")) + .subscription(({ ctx }) => { + return observable((emit) => { + const unsubscribes: (() => void)[] = []; + const innerHandler = clusterInfoRequestHandler.handler(ctx.integration, {}); + const unsubscribe = innerHandler.subscribe((healthInfo) => { + emit.next(healthInfo); + }); + unsubscribes.push(unsubscribe); + return () => { + unsubscribe(); + }; + }); + }), }); diff --git a/packages/api/src/router/widgets/index.ts b/packages/api/src/router/widgets/index.ts index 7f030a4bb..ce39bf9f7 100644 --- a/packages/api/src/router/widgets/index.ts +++ b/packages/api/src/router/widgets/index.ts @@ -7,6 +7,8 @@ import { healthMonitoringRouter } from "./health-monitoring"; import { indexerManagerRouter } from "./indexer-manager"; import { mediaRequestsRouter } from "./media-requests"; import { mediaServerRouter } from "./media-server"; +import { mediaTranscodingRouter } from "./media-transcoding"; +import { minecraftRouter } from "./minecraft"; import { notebookRouter } from "./notebook"; import { rssFeedRouter } from "./rssFeed"; import { smartHomeRouter } from "./smart-home"; @@ -25,4 +27,6 @@ export const widgetRouter = createTRPCRouter({ rssFeed: rssFeedRouter, indexerManager: indexerManagerRouter, healthMonitoring: healthMonitoringRouter, + mediaTranscoding: mediaTranscodingRouter, + minecraft: minecraftRouter, }); diff --git a/packages/api/src/router/widgets/indexer-manager.ts b/packages/api/src/router/widgets/indexer-manager.ts index 19dedb595..2bbf1356d 100644 --- a/packages/api/src/router/widgets/indexer-manager.ts +++ b/packages/api/src/router/widgets/indexer-manager.ts @@ -9,7 +9,7 @@ import { indexerManagerRequestHandler } from "@homarr/request-handler/indexer-ma import type { IntegrationAction } from "../../middlewares/integration"; import { createManyIntegrationMiddleware } from "../../middlewares/integration"; -import { createTRPCRouter, publicProcedure } from "../../trpc"; +import { createTRPCRouter, protectedProcedure, publicProcedure } from "../../trpc"; const createIndexerManagerIntegrationMiddleware = (action: IntegrationAction) => createManyIntegrationMiddleware(action, ...getIntegrationKindsByCategory("indexerManager")); @@ -54,7 +54,7 @@ export const indexerManagerRouter = createTRPCRouter({ }; }); }), - testAllIndexers: publicProcedure + testAllIndexers: protectedProcedure .unstable_concat(createIndexerManagerIntegrationMiddleware("interact")) .mutation(async ({ ctx }) => { await Promise.all( diff --git a/packages/api/src/router/widgets/media-server.ts b/packages/api/src/router/widgets/media-server.ts index c567c21a2..8d3fe4537 100644 --- a/packages/api/src/router/widgets/media-server.ts +++ b/packages/api/src/router/widgets/media-server.ts @@ -21,6 +21,7 @@ export const mediaServerRouter = createTRPCRouter({ const { data } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false }); return { integrationId: integration.id, + integrationKind: integration.kind, sessions: data, }; }), diff --git a/packages/api/src/router/widgets/media-transcoding.ts b/packages/api/src/router/widgets/media-transcoding.ts new file mode 100644 index 000000000..d6d1ce7e8 --- /dev/null +++ b/packages/api/src/router/widgets/media-transcoding.ts @@ -0,0 +1,28 @@ +import { getIntegrationKindsByCategory } from "@homarr/definitions"; +import { mediaTranscodingRequestHandler } from "@homarr/request-handler/media-transcoding"; +import { validation } from "@homarr/validation"; + +import type { IntegrationAction } from "../../middlewares/integration"; +import { createOneIntegrationMiddleware } from "../../middlewares/integration"; +import { createTRPCRouter, publicProcedure } from "../../trpc"; + +const createIndexerManagerIntegrationMiddleware = (action: IntegrationAction) => + createOneIntegrationMiddleware(action, ...getIntegrationKindsByCategory("mediaTranscoding")); + +export const mediaTranscodingRouter = createTRPCRouter({ + getDataAsync: publicProcedure + .unstable_concat(createIndexerManagerIntegrationMiddleware("query")) + .input(validation.common.paginated.pick({ page: true, pageSize: true })) + .query(async ({ ctx, input }) => { + const innerHandler = mediaTranscodingRequestHandler.handler(ctx.integration, { + pageOffset: input.page, + pageSize: input.pageSize, + }); + const { data } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false }); + + return { + integrationId: ctx.integration.id, + data, + }; + }), +}); diff --git a/packages/api/src/router/widgets/minecraft.ts b/packages/api/src/router/widgets/minecraft.ts new file mode 100644 index 000000000..ab1d4c7fb --- /dev/null +++ b/packages/api/src/router/widgets/minecraft.ts @@ -0,0 +1,36 @@ +import { observable } from "@trpc/server/observable"; +import { z } from "zod"; + +import type { MinecraftServerStatus } from "@homarr/request-handler/minecraft-server-status"; +import { minecraftServerStatusRequestHandler } from "@homarr/request-handler/minecraft-server-status"; + +import { createTRPCRouter, publicProcedure } from "../../trpc"; + +const serverStatusInputSchema = z.object({ + domain: z.string().nonempty(), + isBedrockServer: z.boolean(), +}); +export const minecraftRouter = createTRPCRouter({ + getServerStatus: publicProcedure.input(serverStatusInputSchema).query(async ({ input }) => { + const innerHandler = minecraftServerStatusRequestHandler.handler({ + isBedrockServer: input.isBedrockServer, + domain: input.domain, + }); + return await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: true }); + }), + subscribeServerStatus: publicProcedure.input(serverStatusInputSchema).subscription(({ input }) => { + return observable((emit) => { + const innerHandler = minecraftServerStatusRequestHandler.handler({ + isBedrockServer: input.isBedrockServer, + domain: input.domain, + }); + const unsubscribe = innerHandler.subscribe((data) => { + emit.next(data); + }); + + return () => { + unsubscribe(); + }; + }); + }), +}); diff --git a/packages/api/src/router/widgets/notebook.ts b/packages/api/src/router/widgets/notebook.ts index 8fd369630..e9c3f5cff 100644 --- a/packages/api/src/router/widgets/notebook.ts +++ b/packages/api/src/router/widgets/notebook.ts @@ -2,13 +2,13 @@ import { TRPCError } from "@trpc/server"; import SuperJSON from "superjson"; import { eq } from "@homarr/db"; -import { items } from "@homarr/db/schema/sqlite"; +import { items } from "@homarr/db/schema"; import { z } from "@homarr/validation"; -import { createTRPCRouter, publicProcedure } from "../../trpc"; +import { createTRPCRouter, protectedProcedure } from "../../trpc"; export const notebookRouter = createTRPCRouter({ - updateContent: publicProcedure + updateContent: protectedProcedure .input( z.object({ itemId: z.string(), diff --git a/packages/api/src/router/widgets/smart-home.ts b/packages/api/src/router/widgets/smart-home.ts index 1b8b6ec64..d1a1fde85 100644 --- a/packages/api/src/router/widgets/smart-home.ts +++ b/packages/api/src/router/widgets/smart-home.ts @@ -7,7 +7,7 @@ import { z } from "@homarr/validation"; import type { IntegrationAction } from "../../middlewares/integration"; import { createOneIntegrationMiddleware } from "../../middlewares/integration"; -import { createTRPCRouter, publicProcedure } from "../../trpc"; +import { createTRPCRouter, protectedProcedure, publicProcedure } from "../../trpc"; const createSmartHomeIntegrationMiddleware = (action: IntegrationAction) => createOneIntegrationMiddleware(action, ...getIntegrationKindsByCategory("smartHomeServer")); @@ -41,7 +41,7 @@ export const smartHomeRouter = createTRPCRouter({ }; }); }), - switchEntity: publicProcedure + switchEntity: protectedProcedure .unstable_concat(createSmartHomeIntegrationMiddleware("interact")) .input(z.object({ entityId: z.string() })) .mutation(async ({ ctx: { integration }, input }) => { @@ -53,7 +53,7 @@ export const smartHomeRouter = createTRPCRouter({ return success; }), - executeAutomation: publicProcedure + executeAutomation: protectedProcedure .unstable_concat(createSmartHomeIntegrationMiddleware("interact")) .input(z.object({ automationId: z.string() })) .mutation(async ({ ctx: { integration }, input }) => { diff --git a/packages/api/src/server.ts b/packages/api/src/server.ts index c7522c0af..08fc5e1e3 100644 --- a/packages/api/src/server.ts +++ b/packages/api/src/server.ts @@ -9,7 +9,7 @@ import { auth } from "@homarr/auth/next"; * handling a tRPC call from a React Server Component. */ const createContext = cache(async () => { - const heads = new Headers(headers()); + const heads = new Headers(await headers()); heads.set("x-trpc-source", "rsc"); return createTRPCContext({ diff --git a/packages/api/src/shared.ts b/packages/api/src/shared.ts new file mode 100644 index 000000000..b8ebcfcc6 --- /dev/null +++ b/packages/api/src/shared.ts @@ -0,0 +1,38 @@ +/** + * Creates a headers callback for a given source + * It will set the x-trpc-source header and cookies if needed + * @param source trpc source request comes from + * @returns headers callback + */ +export function createHeadersCallbackForSource(source: string) { + return async () => { + const headers = new Headers(); + headers.set("x-trpc-source", source); + + const cookies = await importCookiesAsync(); + // We need to set cookie for ssr requests (for example with useSuspenseQuery or middleware) + if (cookies) { + headers.set("cookie", cookies); + } + + return headers; + }; +} + +/** + * This is a workarround as cookies are not passed to the server + * when using useSuspenseQuery or middleware + * @returns cookie string on server or null on client + */ +async function importCookiesAsync() { + if (typeof window !== "undefined") { + return null; + } + + const { cookies } = await import("next/headers"); + + return (await cookies()) + .getAll() + .map(({ name, value }) => `${name}=${value}`) + .join(";"); +} diff --git a/packages/api/src/trpc.ts b/packages/api/src/trpc.ts index aec73eaf1..6f88a8cd2 100644 --- a/packages/api/src/trpc.ts +++ b/packages/api/src/trpc.ts @@ -12,11 +12,14 @@ import type { OpenApiMeta } from "trpc-to-openapi"; import type { Session } from "@homarr/auth"; import { FlattenError } from "@homarr/common"; +import { userAgent } from "@homarr/common/server"; import { db } from "@homarr/db"; -import type { GroupPermissionKey } from "@homarr/definitions"; +import type { GroupPermissionKey, OnboardingStep } from "@homarr/definitions"; import { logger } from "@homarr/log"; import { ZodError } from "@homarr/validation"; +import { getOnboardingOrFallbackAsync } from "./router/onboard/onboard-queries"; + /** * 1. CONTEXT * @@ -37,6 +40,7 @@ export const createTRPCContext = (opts: { headers: Headers; session: Session | n return { session, + deviceType: userAgent(opts.headers).device.type, db, }; }; @@ -138,3 +142,19 @@ export const permissionRequiredProcedure = { }); }, }; + +export const onboardingProcedure = { + requiresStep: (step: OnboardingStep) => { + return publicProcedure.use(async ({ ctx, input, next }) => { + const currentStep = await getOnboardingOrFallbackAsync(ctx.db).then(({ current }) => current); + if (currentStep !== step) { + throw new TRPCError({ + code: "FORBIDDEN", + message: "Step denied", + }); + } + + return next({ input, ctx }); + }); + }, +}; diff --git a/packages/auth/adapter.ts b/packages/auth/adapter.ts index 69876b1f4..30984a403 100644 --- a/packages/auth/adapter.ts +++ b/packages/auth/adapter.ts @@ -3,7 +3,7 @@ import { DrizzleAdapter } from "@auth/drizzle-adapter"; import type { Database } from "@homarr/db"; import { and, eq } from "@homarr/db"; -import { accounts, sessions, users } from "@homarr/db/schema/sqlite"; +import { accounts, sessions, users } from "@homarr/db/schema"; import type { SupportedAuthProvider } from "@homarr/definitions"; export const createAdapter = (db: Database, provider: SupportedAuthProvider | "unknown"): Adapter => { diff --git a/packages/auth/callbacks.ts b/packages/auth/callbacks.ts index d5fac0b7a..8f1168ad8 100644 --- a/packages/auth/callbacks.ts +++ b/packages/auth/callbacks.ts @@ -4,7 +4,7 @@ import type { NextAuthConfig } from "next-auth"; import type { Session } from "@homarr/auth"; import type { Database } from "@homarr/db"; import { eq, inArray } from "@homarr/db"; -import { groupMembers, groupPermissions, users } from "@homarr/db/schema/sqlite"; +import { groupMembers, groupPermissions, users } from "@homarr/db/schema"; import { getPermissionsWithChildren } from "@homarr/definitions"; export const getCurrentUserPermissionsAsync = async (db: Database, userId: string) => { diff --git a/packages/auth/configuration.ts b/packages/auth/configuration.ts index 4c00a0b20..96bba6723 100644 --- a/packages/auth/configuration.ts +++ b/packages/auth/configuration.ts @@ -8,7 +8,7 @@ import type { SupportedAuthProvider } from "@homarr/definitions"; import { createAdapter } from "./adapter"; import { createSessionCallback } from "./callbacks"; -import { env } from "./env.mjs"; +import { env } from "./env"; import { createSignInEventHandler } from "./events"; import { createCredentialsConfiguration, createLdapConfiguration } from "./providers/credentials/credentials-provider"; import { EmptyNextAuthProvider } from "./providers/empty/empty-provider"; @@ -74,7 +74,7 @@ export const createConfiguration = ( userId: user.id, }); - cookies().set(sessionTokenCookieName, sessionToken, { + (await cookies()).set(sessionTokenCookieName, sessionToken, { path: "/", expires: expires, httpOnly: true, @@ -89,7 +89,6 @@ export const createConfiguration = ( signIn: createSignInEventHandler(db), }, redirectProxyUrl: createRedirectUri(headers, "/api/auth"), - secret: "secret-is-not-defined-yet", // TODO: This should be added later session: { strategy: "database", maxAge: env.AUTH_SESSION_EXPIRY_TIME, @@ -100,8 +99,9 @@ export const createConfiguration = ( error: "/auth/login", }, jwt: { - encode() { - const cookie = cookies().get(sessionTokenCookieName)?.value; + // eslint-disable-next-line no-restricted-syntax + async encode() { + const cookie = (await cookies()).get(sessionTokenCookieName)?.value; return cookie ?? ""; }, diff --git a/packages/auth/env.mjs b/packages/auth/env.ts similarity index 72% rename from packages/auth/env.mjs rename to packages/auth/env.ts index de1faa36f..6d9aa3354 100644 --- a/packages/auth/env.mjs +++ b/packages/auth/env.ts @@ -1,10 +1,9 @@ import { createEnv } from "@t3-oss/env-nextjs"; import { z } from "zod"; -const trueStrings = ["1", "yes", "t", "true"]; -const falseStrings = ["0", "no", "f", "false"]; +import { createBooleanSchema, createDurationSchema, shouldSkipEnvValidation } from "@homarr/common/env-validation"; +import { supportedAuthProviders } from "@homarr/definitions"; -const supportedAuthProviders = ["credentials", "oidc", "ldap"]; const authProvidersSchema = z .string() .min(1) @@ -14,7 +13,7 @@ const authProvidersSchema = z .toLowerCase() .split(",") .filter((provider) => { - if (supportedAuthProviders.includes(provider)) return true; + if (supportedAuthProviders.some((supportedProvider) => supportedProvider === provider)) return true; else if (!provider) console.log("One or more of the entries for AUTH_PROVIDER could not be parsed and/or returned null."); else console.log(`The value entered for AUTH_PROVIDER "${provider}" is incorrect.`); @@ -23,48 +22,13 @@ const authProvidersSchema = z ) .default("credentials"); -const createDurationSchema = (defaultValue) => - z - .string() - .regex(/^\d+[smhd]?$/) - .default(defaultValue) - .transform((duration) => { - const lastChar = duration[duration.length - 1]; - if (!isNaN(Number(lastChar))) { - return Number(defaultValue); - } - - const multipliers = { - s: 1, - m: 60, - h: 60 * 60, - d: 60 * 60 * 24, - }; - const numberDuration = Number(duration.slice(0, -1)); - const multiplier = multipliers[lastChar]; - - return numberDuration * multiplier; - }); - -const booleanSchema = z - .string() - .default("false") - .transform((value, ctx) => { - const normalized = value.trim().toLowerCase(); - if (trueStrings.includes(normalized)) return true; - if (falseStrings.includes(normalized)) return false; - - throw new Error(`Invalid boolean value for ${ctx.path.join(".")}`); - }); - -const skipValidation = Boolean(process.env.CI) || Boolean(process.env.SKIP_ENV_VALIDATION); +const skipValidation = shouldSkipEnvValidation(); const authProviders = skipValidation ? [] : authProvidersSchema.parse(process.env.AUTH_PROVIDERS); export const env = createEnv({ server: { AUTH_LOGOUT_REDIRECT_URL: z.string().url().optional(), AUTH_SESSION_EXPIRY_TIME: createDurationSchema("30d"), - AUTH_SECRET: process.env.NODE_ENV === "production" ? z.string().min(1) : z.string().min(1).optional(), AUTH_PROVIDERS: authProvidersSchema, ...(authProviders.includes("oidc") ? { @@ -72,9 +36,10 @@ export const env = createEnv({ AUTH_OIDC_CLIENT_ID: z.string().min(1), AUTH_OIDC_CLIENT_SECRET: z.string().min(1), AUTH_OIDC_CLIENT_NAME: z.string().min(1).default("OIDC"), - AUTH_OIDC_AUTO_LOGIN: booleanSchema, + AUTH_OIDC_AUTO_LOGIN: createBooleanSchema(false), AUTH_OIDC_SCOPE_OVERWRITE: z.string().min(1).default("openid email profile groups"), AUTH_OIDC_GROUPS_ATTRIBUTE: z.string().default("groups"), // Is used in the signIn event to assign the correct groups, key is from object of decoded id_token + AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE: z.string().optional(), } : {}), ...(authProviders.includes("ldap") @@ -98,7 +63,6 @@ export const env = createEnv({ runtimeEnv: { AUTH_LOGOUT_REDIRECT_URL: process.env.AUTH_LOGOUT_REDIRECT_URL, AUTH_SESSION_EXPIRY_TIME: process.env.AUTH_SESSION_EXPIRY_TIME, - AUTH_SECRET: process.env.AUTH_SECRET, AUTH_PROVIDERS: process.env.AUTH_PROVIDERS, AUTH_LDAP_BASE: process.env.AUTH_LDAP_BASE, AUTH_LDAP_BIND_DN: process.env.AUTH_LDAP_BIND_DN, @@ -119,6 +83,7 @@ export const env = createEnv({ AUTH_LDAP_USER_MAIL_ATTRIBUTE: process.env.AUTH_LDAP_USER_MAIL_ATTRIBUTE, AUTH_LDAP_USERNAME_FILTER_EXTRA_ARG: process.env.AUTH_LDAP_USERNAME_FILTER_EXTRA_ARG, AUTH_OIDC_AUTO_LOGIN: process.env.AUTH_OIDC_AUTO_LOGIN, + AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE: process.env.AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE, }, skipValidation, }); diff --git a/packages/auth/events.ts b/packages/auth/events.ts index 2c636d14b..2c8c68dd7 100644 --- a/packages/auth/events.ts +++ b/packages/auth/events.ts @@ -4,11 +4,12 @@ import type { NextAuthConfig } from "next-auth"; import { and, eq, inArray } from "@homarr/db"; import type { Database } from "@homarr/db"; -import { groupMembers, groups, users } from "@homarr/db/schema/sqlite"; +import { groupMembers, groups, users } from "@homarr/db/schema"; import { colorSchemeCookieKey, everyoneGroup } from "@homarr/definitions"; import { logger } from "@homarr/log"; -import { env } from "./env.mjs"; +import { env } from "./env"; +import { extractProfileName } from "./providers/oidc/oidc-provider"; export const createSignInEventHandler = (db: Database): Exclude["signIn"] => { return async ({ user, profile }) => { @@ -43,18 +44,24 @@ export const createSignInEventHandler = (db: Database): Exclude - createConfiguration(provider, headers(), useSecureCookies); +export const createHandlersAsync = async (provider: SupportedAuthProvider | "unknown", useSecureCookies: boolean) => + createConfiguration(provider, await headers(), useSecureCookies); export { getSessionFromTokenAsync as getSessionFromToken, sessionTokenCookieName } from "./session"; diff --git a/packages/auth/package.json b/packages/auth/package.json index 6b590a730..a4c57c9eb 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -11,7 +11,7 @@ "./client": "./client.ts", "./server": "./server.ts", "./shared": "./shared.ts", - "./env.mjs": "./env.mjs" + "./env": "./env.ts" }, "main": "./index.ts", "types": "./index.ts", @@ -33,11 +33,11 @@ "@t3-oss/env-nextjs": "^0.11.1", "bcrypt": "^5.1.1", "cookies": "^0.9.1", - "ldapts": "7.2.2", - "next": "^14.2.20", + "ldapts": "7.3.1", + "next": "15.1.4", "next-auth": "5.0.0-beta.25", - "react": "^19.0.0", - "react-dom": "^19.0.0" + "react": "19.0.0", + "react-dom": "19.0.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", @@ -45,8 +45,8 @@ "@homarr/tsconfig": "workspace:^0.1.0", "@types/bcrypt": "5.0.2", "@types/cookies": "0.9.0", - "eslint": "^9.16.0", + "eslint": "^9.18.0", "prettier": "^3.4.2", - "typescript": "^5.7.2" + "typescript": "^5.7.3" } } diff --git a/packages/auth/permissions/integration-query-permissions.ts b/packages/auth/permissions/integration-query-permissions.ts index 4ee7a31c2..13d65aca8 100644 --- a/packages/auth/permissions/integration-query-permissions.ts +++ b/packages/auth/permissions/integration-query-permissions.ts @@ -2,7 +2,7 @@ import type { Session } from "next-auth"; import type { Database } from "@homarr/db"; import { and, eq, inArray, or } from "@homarr/db"; -import { boards, boardUserPermissions, groupMembers } from "@homarr/db/schema/sqlite"; +import { boards, boardUserPermissions, groupMembers } from "@homarr/db/schema"; import type { IntegrationPermission } from "@homarr/definitions"; import { constructIntegrationPermissions } from "./integration-permissions"; diff --git a/packages/auth/permissions/integrations-with-permissions.ts b/packages/auth/permissions/integrations-with-permissions.ts index 64fe09087..76cae6c93 100644 --- a/packages/auth/permissions/integrations-with-permissions.ts +++ b/packages/auth/permissions/integrations-with-permissions.ts @@ -1,7 +1,7 @@ import type { Session } from "next-auth"; import { db, eq, inArray } from "@homarr/db"; -import { groupMembers, integrationGroupPermissions, integrationUserPermissions } from "@homarr/db/schema/sqlite"; +import { groupMembers, integrationGroupPermissions, integrationUserPermissions } from "@homarr/db/schema"; import { constructIntegrationPermissions } from "./integration-permissions"; diff --git a/packages/auth/permissions/test/integration-query-permissions.spec.ts b/packages/auth/permissions/test/integration-query-permissions.spec.ts index faf527d92..a1d9f52ed 100644 --- a/packages/auth/permissions/test/integration-query-permissions.spec.ts +++ b/packages/auth/permissions/test/integration-query-permissions.spec.ts @@ -3,14 +3,7 @@ import { describe, expect, test, vi } from "vitest"; import type { InferInsertModel } from "@homarr/db"; import { createId } from "@homarr/db"; -import { - boardGroupPermissions, - boards, - boardUserPermissions, - groupMembers, - groups, - users, -} from "@homarr/db/schema/sqlite"; +import { boardGroupPermissions, boards, boardUserPermissions, groupMembers, groups, users } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import * as integrationPermissions from "../integration-permissions"; diff --git a/packages/auth/providers/check-provider.ts b/packages/auth/providers/check-provider.ts index fd483465b..b38e3c3ad 100644 --- a/packages/auth/providers/check-provider.ts +++ b/packages/auth/providers/check-provider.ts @@ -1,6 +1,6 @@ import type { SupportedAuthProvider } from "@homarr/definitions"; -import { env } from "../env.mjs"; +import { env } from "../env"; export const isProviderEnabled = (provider: SupportedAuthProvider) => { // The question mark is placed there because isProviderEnabled is called during static build of about page diff --git a/packages/auth/providers/credentials/authorization/basic-authorization.ts b/packages/auth/providers/credentials/authorization/basic-authorization.ts index 6357df7c6..cdce3fe9e 100644 --- a/packages/auth/providers/credentials/authorization/basic-authorization.ts +++ b/packages/auth/providers/credentials/authorization/basic-authorization.ts @@ -2,7 +2,7 @@ import bcrypt from "bcrypt"; import type { Database } from "@homarr/db"; import { and, eq } from "@homarr/db"; -import { users } from "@homarr/db/schema/sqlite"; +import { users } from "@homarr/db/schema"; import { logger } from "@homarr/log"; import type { validation, z } from "@homarr/validation"; diff --git a/packages/auth/providers/credentials/authorization/ldap-authorization.ts b/packages/auth/providers/credentials/authorization/ldap-authorization.ts index cae75f693..bf793ba05 100644 --- a/packages/auth/providers/credentials/authorization/ldap-authorization.ts +++ b/packages/auth/providers/credentials/authorization/ldap-authorization.ts @@ -2,12 +2,12 @@ import { CredentialsSignin } from "@auth/core/errors"; import type { Database, InferInsertModel } from "@homarr/db"; import { and, createId, eq } from "@homarr/db"; -import { users } from "@homarr/db/schema/sqlite"; +import { users } from "@homarr/db/schema"; import { logger } from "@homarr/log"; import type { validation } from "@homarr/validation"; import { z } from "@homarr/validation"; -import { env } from "../../../env.mjs"; +import { env } from "../../../env"; import { LdapClient } from "../ldap-client"; export const authorizeWithLdapCredentialsAsync = async ( diff --git a/packages/auth/providers/credentials/ldap-client.ts b/packages/auth/providers/credentials/ldap-client.ts index 7c266360f..4dc48e2a8 100644 --- a/packages/auth/providers/credentials/ldap-client.ts +++ b/packages/auth/providers/credentials/ldap-client.ts @@ -3,7 +3,7 @@ import { Client } from "ldapts"; import { objectEntries } from "@homarr/common"; -import { env } from "../../env.mjs"; +import { env } from "../../env"; export interface BindOptions { distinguishedName: string; diff --git a/packages/auth/providers/filter-providers.ts b/packages/auth/providers/filter-providers.ts index 1ee2ad38e..236bfe6ac 100644 --- a/packages/auth/providers/filter-providers.ts +++ b/packages/auth/providers/filter-providers.ts @@ -1,6 +1,6 @@ import type { Provider } from "next-auth/providers"; -import { env } from "../env.mjs"; +import { env } from "../env"; export const filterProviders = (providers: Exclude unknown>[]) => { // During build this will be undefined, so we default to an empty array diff --git a/packages/auth/providers/oidc/oidc-provider.ts b/packages/auth/providers/oidc/oidc-provider.ts index 925e7d1dd..82328b3ff 100644 --- a/packages/auth/providers/oidc/oidc-provider.ts +++ b/packages/auth/providers/oidc/oidc-provider.ts @@ -1,18 +1,10 @@ import type { ReadonlyHeaders } from "next/dist/server/web/spec-extension/adapters/headers"; -import type { OIDCConfig } from "next-auth/providers"; +import type { OIDCConfig } from "@auth/core/providers"; +import type { Profile } from "@auth/core/types"; -import { env } from "../../env.mjs"; +import { env } from "../../env"; import { createRedirectUri } from "../../redirect"; -interface Profile { - sub: string; - name: string; - email: string; - groups: string[]; - preferred_username: string; - email_verified: boolean; -} - export const OidcProvider = (headers: ReadonlyHeaders | null): OIDCConfig => ({ id: "oidc", name: env.AUTH_OIDC_CLIENT_NAME, @@ -23,16 +15,33 @@ export const OidcProvider = (headers: ReadonlyHeaders | null): OIDCConfig { + if (!env.AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE) { + // Use the name as the username if the preferred_username is an email address + return profile.preferred_username?.includes("@") ? profile.name : profile.preferred_username; + } + + return profile[env.AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE as keyof typeof profile] as string; +}; diff --git a/packages/auth/providers/test/basic-authorization.spec.ts b/packages/auth/providers/test/basic-authorization.spec.ts index b828d2784..8955ea83a 100644 --- a/packages/auth/providers/test/basic-authorization.spec.ts +++ b/packages/auth/providers/test/basic-authorization.spec.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "vitest"; import { createId } from "@homarr/db"; -import { users } from "@homarr/db/schema/sqlite"; +import { users } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import { createSaltAsync, hashPasswordAsync } from "../../security"; diff --git a/packages/auth/providers/test/ldap-authorization.spec.ts b/packages/auth/providers/test/ldap-authorization.spec.ts index c78fba30f..50f35399e 100644 --- a/packages/auth/providers/test/ldap-authorization.spec.ts +++ b/packages/auth/providers/test/ldap-authorization.spec.ts @@ -3,13 +3,13 @@ import { describe, expect, test, vi } from "vitest"; import type { Database } from "@homarr/db"; import { and, createId, eq } from "@homarr/db"; -import { groups, users } from "@homarr/db/schema/sqlite"; +import { groups, users } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import { authorizeWithLdapCredentialsAsync } from "../credentials/authorization/ldap-authorization"; import * as ldapClient from "../credentials/ldap-client"; -vi.mock("../../env.mjs", () => ({ +vi.mock("../../env", () => ({ env: { AUTH_LDAP_BIND_DN: "bind_dn", AUTH_LDAP_BIND_PASSWORD: "bind_password", diff --git a/packages/auth/redirect.ts b/packages/auth/redirect.ts index 94ed327a1..c27e6eaeb 100644 --- a/packages/auth/redirect.ts +++ b/packages/auth/redirect.ts @@ -8,12 +8,16 @@ import { extractBaseUrlFromHeaders } from "@homarr/common"; * @param pathname * @returns */ -export const createRedirectUri = (headers: ReadonlyHeaders | null, pathname: string) => { +export const createRedirectUri = ( + headers: ReadonlyHeaders | null, + pathname: string, + fallbackProtocol: "http" | "https" = "http", +) => { if (!headers) { return pathname; } - const baseUrl = extractBaseUrlFromHeaders(headers); + const baseUrl = extractBaseUrlFromHeaders(headers, fallbackProtocol); const path = pathname.startsWith("/") ? pathname : `/${pathname}`; diff --git a/packages/auth/test/adapter.spec.ts b/packages/auth/test/adapter.spec.ts index 7c74ffa4e..d20ae3d1a 100644 --- a/packages/auth/test/adapter.spec.ts +++ b/packages/auth/test/adapter.spec.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "vitest"; -import { users } from "@homarr/db/schema/sqlite"; +import { users } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import { createAdapter } from "../adapter"; diff --git a/packages/auth/test/callbacks.spec.ts b/packages/auth/test/callbacks.spec.ts index d2da21a3b..6a1f52e2b 100644 --- a/packages/auth/test/callbacks.spec.ts +++ b/packages/auth/test/callbacks.spec.ts @@ -3,7 +3,7 @@ import type { AdapterUser } from "@auth/core/adapters"; import type { JWT } from "next-auth/jwt"; import { describe, expect, test, vi } from "vitest"; -import { groupMembers, groupPermissions, groups, users } from "@homarr/db/schema/sqlite"; +import { groupMembers, groupPermissions, groups, users } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import * as definitions from "@homarr/definitions"; diff --git a/packages/auth/test/events.spec.ts b/packages/auth/test/events.spec.ts index 272612ce9..a2783bad7 100644 --- a/packages/auth/test/events.spec.ts +++ b/packages/auth/test/events.spec.ts @@ -5,13 +5,13 @@ import { describe, expect, test, vi } from "vitest"; import { eq } from "@homarr/db"; import type { Database } from "@homarr/db"; -import { groupMembers, groups, users } from "@homarr/db/schema/sqlite"; +import { groupMembers, groups, users } from "@homarr/db/schema"; import { createDb } from "@homarr/db/test"; import { colorSchemeCookieKey, everyoneGroup } from "@homarr/definitions"; import { createSignInEventHandler } from "../events"; -vi.mock("../env.mjs", () => { +vi.mock("../env", () => { return { env: { AUTH_OIDC_GROUPS_ATTRIBUTE: "someRandomGroupsKey", @@ -29,7 +29,7 @@ vi.mock("next/headers", async (importOriginal) => { vi.spyOn(result, "set"); - const cookies = () => result; + const cookies = () => Promise.resolve(result); return { ...mod, cookies } satisfies HeadersExport; }); @@ -238,7 +238,7 @@ describe("createSignInEventHandler should create signInEventHandler", () => { }); // Assert - expect(cookies().set).toHaveBeenCalledWith( + expect((await cookies()).set).toHaveBeenCalledWith( colorSchemeCookieKey, "dark", expect.objectContaining({ diff --git a/packages/certificates/eslint.config.js b/packages/certificates/eslint.config.js new file mode 100644 index 000000000..5b19b6f8a --- /dev/null +++ b/packages/certificates/eslint.config.js @@ -0,0 +1,9 @@ +import baseConfig from "@homarr/eslint-config/base"; + +/** @type {import('typescript-eslint').Config} */ +export default [ + { + ignores: [], + }, + ...baseConfig, +]; diff --git a/packages/certificates/package.json b/packages/certificates/package.json new file mode 100644 index 000000000..26dca44ca --- /dev/null +++ b/packages/certificates/package.json @@ -0,0 +1,35 @@ +{ + "name": "@homarr/certificates", + "version": "0.1.0", + "private": true, + "license": "MIT", + "type": "module", + "exports": { + "./server": "./src/server.ts" + }, + "typesVersions": { + "*": { + "*": [ + "src/*" + ] + } + }, + "scripts": { + "clean": "rm -rf .turbo node_modules", + "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", + "typecheck": "tsc --noEmit" + }, + "prettier": "@homarr/prettier-config", + "dependencies": { + "@homarr/common": "workspace:^0.1.0", + "undici": "7.2.3" + }, + "devDependencies": { + "@homarr/eslint-config": "workspace:^0.2.0", + "@homarr/prettier-config": "workspace:^0.1.0", + "@homarr/tsconfig": "workspace:^0.1.0", + "eslint": "^9.18.0", + "typescript": "^5.7.3" + } +} diff --git a/packages/certificates/src/server.ts b/packages/certificates/src/server.ts new file mode 100644 index 000000000..334c1f47f --- /dev/null +++ b/packages/certificates/src/server.ts @@ -0,0 +1,87 @@ +import fsSync from "node:fs"; +import fs from "node:fs/promises"; +import { Agent } from "node:https"; +import path from "node:path"; +import { rootCertificates } from "node:tls"; +import axios from "axios"; +import { fetch } from "undici"; + +import { LoggingAgent } from "@homarr/common/server"; + +const getCertificateFolder = () => { + return process.env.NODE_ENV === "production" + ? path.join("/appdata", "trusted-certificates") + : process.env.LOCAL_CERTIFICATE_PATH; +}; + +export const loadCustomRootCertificatesAsync = async () => { + const folder = getCertificateFolder(); + + if (!folder) { + return []; + } + + if (!fsSync.existsSync(folder)) { + await fs.mkdir(folder, { recursive: true }); + } + + const dirContent = await fs.readdir(folder); + return await Promise.all( + dirContent + .filter((file) => file.endsWith(".crt")) + .map(async (file) => ({ + content: await fs.readFile(path.join(folder, file), "utf8"), + fileName: file, + })), + ); +}; + +export const removeCustomRootCertificateAsync = async (fileName: string) => { + const folder = getCertificateFolder(); + if (!folder) { + return; + } + + await fs.rm(path.join(folder, fileName)); +}; + +export const addCustomRootCertificateAsync = async (fileName: string, content: string) => { + const folder = getCertificateFolder(); + if (!folder) { + throw new Error( + "When you want to use custom certificates locally you need to set LOCAL_CERTIFICATE_PATH to an absolute path", + ); + } + + if (fileName.includes("/")) { + throw new Error("Invalid file name"); + } + + await fs.writeFile(path.join(folder, fileName), content); +}; + +export const createCertificateAgentAsync = async () => { + const customCertificates = await loadCustomRootCertificatesAsync(); + return new LoggingAgent({ + connect: { + ca: rootCertificates.concat(customCertificates.map((cert) => cert.content)), + }, + }); +}; + +export const createAxiosCertificateInstanceAsync = async () => { + const customCertificates = await loadCustomRootCertificatesAsync(); + return axios.create({ + httpsAgent: new Agent({ + ca: rootCertificates.concat(customCertificates.map((cert) => cert.content)), + }), + }); +}; + +export const fetchWithTrustedCertificatesAsync: typeof fetch = async (url, options) => { + const agent = await createCertificateAgentAsync(); + return fetch(url, { + ...options, + dispatcher: agent, + }); +}; diff --git a/packages/certificates/tsconfig.json b/packages/certificates/tsconfig.json new file mode 100644 index 000000000..cbe8483d9 --- /dev/null +++ b/packages/certificates/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@homarr/tsconfig/base.json", + "compilerOptions": { + "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" + }, + "include": ["*.ts", "src"], + "exclude": ["node_modules"] +} diff --git a/packages/cli/package.json b/packages/cli/package.json index dda211f4a..6fbd90a33 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -33,7 +33,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/cli/src/commands/reset-password.ts b/packages/cli/src/commands/reset-password.ts index a2a31cac0..ee4383205 100644 --- a/packages/cli/src/commands/reset-password.ts +++ b/packages/cli/src/commands/reset-password.ts @@ -3,7 +3,7 @@ import { command, string } from "@drizzle-team/brocli"; import { hashPasswordAsync } from "@homarr/auth"; import { generateSecureRandomToken } from "@homarr/common/server"; import { and, db, eq } from "@homarr/db"; -import { sessions, users } from "@homarr/db/schema/sqlite"; +import { sessions, users } from "@homarr/db/schema"; export const resetPassword = command({ name: "reset-password", diff --git a/packages/common/env.ts b/packages/common/env.ts new file mode 100644 index 000000000..fda1b7859 --- /dev/null +++ b/packages/common/env.ts @@ -0,0 +1,29 @@ +import { randomBytes } from "crypto"; +import { createEnv } from "@t3-oss/env-nextjs"; +import { z } from "zod"; + +import { shouldSkipEnvValidation } from "./src/env-validation"; + +const errorSuffix = `, please generate a 64 character secret in hex format or use the following: "${randomBytes(32).toString("hex")}"`; + +export const env = createEnv({ + server: { + SECRET_ENCRYPTION_KEY: z + .string({ + required_error: `SECRET_ENCRYPTION_KEY is required${errorSuffix}`, + }) + .min(64, { + message: `SECRET_ENCRYPTION_KEY has to be 64 characters${errorSuffix}`, + }) + .max(64, { + message: `SECRET_ENCRYPTION_KEY has to be 64 characters${errorSuffix}`, + }) + .regex(/^[0-9a-fA-F]{64}$/, { + message: `SECRET_ENCRYPTION_KEY must only contain hex characters${errorSuffix}`, + }), + }, + runtimeEnv: { + SECRET_ENCRYPTION_KEY: process.env.SECRET_ENCRYPTION_KEY, + }, + skipValidation: shouldSkipEnvValidation(), +}); diff --git a/packages/common/package.json b/packages/common/package.json index 6474a71b7..6e226ab72 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -8,7 +8,9 @@ ".": "./index.ts", "./types": "./src/types.ts", "./server": "./src/server.ts", - "./client": "./src/client.ts" + "./client": "./src/client.ts", + "./env": "./env.ts", + "./env-validation": "./src/env-validation.ts" }, "typesVersions": { "*": { @@ -27,15 +29,17 @@ "dependencies": { "@homarr/log": "workspace:^0.1.0", "dayjs": "^1.11.13", - "next": "^14.2.20", - "react": "^19.0.0", - "tldts": "^6.1.67" + "next": "15.1.4", + "react": "19.0.0", + "react-dom": "19.0.0", + "undici": "7.2.3", + "zod": "^3.24.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/common/src/app-url/base.ts b/packages/common/src/app-url/base.ts deleted file mode 100644 index b189c9352..000000000 --- a/packages/common/src/app-url/base.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as tldts from "tldts"; - -const safeParseTldts = (url: string) => { - try { - return tldts.parse(url); - } catch { - return null; - } -}; - -export const parseAppHrefWithVariables = (url: TInput, currentHref: string): TInput => { - if (!url || url.length === 0) return url; - - const tldtsResult = safeParseTldts(currentHref); - - const urlObject = new URL(currentHref); - - return url - .replaceAll("[homarr_base]", `${urlObject.protocol}//${urlObject.hostname}`) - .replaceAll("[homarr_hostname]", tldtsResult?.hostname ?? "") - .replaceAll("[homarr_domain]", tldtsResult?.domain ?? "") - .replaceAll("[homarr_protocol]", urlObject.protocol.replace(":", "")) as TInput; -}; diff --git a/packages/common/src/app-url/client.ts b/packages/common/src/app-url/client.ts deleted file mode 100644 index 92d16a028..000000000 --- a/packages/common/src/app-url/client.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { parseAppHrefWithVariables } from "./base"; - -export const parseAppHrefWithVariablesClient = (url: TInput): TInput => { - if (typeof window === "undefined") return url; - return parseAppHrefWithVariables(url, window.location.href); -}; diff --git a/packages/common/src/app-url/server.ts b/packages/common/src/app-url/server.ts deleted file mode 100644 index 1f4ff363d..000000000 --- a/packages/common/src/app-url/server.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { headers } from "next/headers"; - -import { extractBaseUrlFromHeaders } from "../url"; -import { parseAppHrefWithVariables } from "./base"; - -export const parseAppHrefWithVariablesServer = (url: TInput): TInput => { - return parseAppHrefWithVariables(url, extractBaseUrlFromHeaders(headers())); -}; diff --git a/packages/common/src/client.ts b/packages/common/src/client.ts index 1a9fcaadf..88fd136c4 100644 --- a/packages/common/src/client.ts +++ b/packages/common/src/client.ts @@ -1,2 +1 @@ -export * from "./app-url/client"; export * from "./revalidate-path-action"; diff --git a/packages/common/src/encryption.ts b/packages/common/src/encryption.ts index cd253a89a..a10451f9f 100644 --- a/packages/common/src/encryption.ts +++ b/packages/common/src/encryption.ts @@ -1,20 +1,12 @@ import crypto from "crypto"; -import { logger } from "@homarr/log"; +import { env } from "../env"; const algorithm = "aes-256-cbc"; //Using AES encryption -const fallbackKey = "0000000000000000000000000000000000000000000000000000000000000000"; -const encryptionKey = process.env.ENCRYPTION_KEY ?? fallbackKey; // Fallback to a default key for local development -if (encryptionKey === fallbackKey) { - logger.warn("Using a fallback encryption key, stored secrets are not secure"); - // We never want to use the fallback key in production - if (process.env.NODE_ENV === "production" && process.env.CI !== "true") { - throw new Error("Encryption key is not set"); - } -} - -const key = Buffer.from(encryptionKey, "hex"); +// We fallback to a key of 0s if the key was not provided because env validation was skipped +// This should only be the case in CI +const key = Buffer.from(env.SECRET_ENCRYPTION_KEY || "0".repeat(64), "hex"); export function encryptSecret(text: string): `${string}.${string}` { const initializationVector = crypto.randomBytes(16); @@ -25,6 +17,10 @@ export function encryptSecret(text: string): `${string}.${string}` { } export function decryptSecret(value: `${string}.${string}`) { + return decryptSecretWithKey(value, key); +} + +export function decryptSecretWithKey(value: `${string}.${string}`, key: Buffer) { const [data, dataIv] = value.split(".") as [string, string]; const initializationVector = Buffer.from(dataIv, "hex"); const encryptedText = Buffer.from(data, "hex"); diff --git a/packages/common/src/env-validation.ts b/packages/common/src/env-validation.ts new file mode 100644 index 000000000..ff884bc0a --- /dev/null +++ b/packages/common/src/env-validation.ts @@ -0,0 +1,42 @@ +import { z } from "zod"; + +const trueStrings = ["1", "yes", "t", "true"]; +const falseStrings = ["0", "no", "f", "false"]; + +export const createBooleanSchema = (defaultValue: boolean) => + z + .string() + .default(defaultValue.toString()) + .transform((value, ctx) => { + const normalized = value.trim().toLowerCase(); + if (trueStrings.includes(normalized)) return true; + if (falseStrings.includes(normalized)) return false; + + throw new Error(`Invalid boolean value for ${ctx.path.join(".")}`); + }); + +export const createDurationSchema = (defaultValue: `${number}${"s" | "m" | "h" | "d"}`) => + z + .string() + .regex(/^\d+[smhd]?$/) + .default(defaultValue) + .transform((duration) => { + const lastChar = duration[duration.length - 1] as "s" | "m" | "h" | "d"; + if (!isNaN(Number(lastChar))) { + return Number(defaultValue); + } + + const multipliers = { + s: 1, + m: 60, + h: 60 * 60, + d: 60 * 60 * 24, + }; + const numberDuration = Number(duration.slice(0, -1)); + const multiplier = multipliers[lastChar]; + + return numberDuration * multiplier; + }); + +export const shouldSkipEnvValidation = () => + Boolean(process.env.CI) || Boolean(process.env.SKIP_ENV_VALIDATION) || process.env.npm_lifecycle_event === "lint"; diff --git a/packages/common/src/fetch-agent.ts b/packages/common/src/fetch-agent.ts new file mode 100644 index 000000000..f19a866af --- /dev/null +++ b/packages/common/src/fetch-agent.ts @@ -0,0 +1,32 @@ +import type { Dispatcher } from "undici"; +import { Agent } from "undici"; + +import { logger } from "@homarr/log"; + +export class LoggingAgent extends Agent { + constructor(...props: ConstructorParameters) { + super(...props); + } + + dispatch(options: Dispatcher.DispatchOptions, handler: Dispatcher.DispatchHandler): boolean { + const url = new URL(`${options.origin as string}${options.path}`); + + // The below code should prevent sensitive data from being logged as + // some integrations use query parameters for auth + url.searchParams.forEach((value, key) => { + if (value === "") return; // Skip empty values + if (/^-?\d{1,12}$/.test(value)) return; // Skip small numbers + if (value === "true" || value === "false") return; // Skip boolean values + if (/^[a-zA-Z]{1,12}$/.test(value)) return; // Skip short strings + if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return; // Skip dates + if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value)) return; // Skip date times + + url.searchParams.set(key, "REDACTED"); + }); + + logger.info( + `Dispatching request ${url.toString().replaceAll("=&", "&")} (${Object.keys(options.headers ?? {}).length} headers)`, + ); + return super.dispatch(options, handler); + } +} diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index f45300e32..cbcec5e2a 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -8,3 +8,4 @@ export * from "./url"; export * from "./number"; export * from "./error"; export * from "./fetch-with-timeout"; +export * from "./theme"; diff --git a/packages/common/src/server.ts b/packages/common/src/server.ts index 136ecfc84..8203e2757 100644 --- a/packages/common/src/server.ts +++ b/packages/common/src/server.ts @@ -1,3 +1,4 @@ -export * from "./app-url/server"; export * from "./security"; export * from "./encryption"; +export * from "./user-agent"; +export * from "./fetch-agent"; diff --git a/apps/tasks/src/test/undici-log-agent-override.spec.ts b/packages/common/src/test/fetch-agent.spec.ts similarity index 98% rename from apps/tasks/src/test/undici-log-agent-override.spec.ts rename to packages/common/src/test/fetch-agent.spec.ts index f237c22e7..064335018 100644 --- a/apps/tasks/src/test/undici-log-agent-override.spec.ts +++ b/packages/common/src/test/fetch-agent.spec.ts @@ -3,7 +3,7 @@ import { describe, expect, test, vi } from "vitest"; import { logger } from "@homarr/log"; -import { LoggingAgent } from "~/undici-log-agent-override"; +import { LoggingAgent } from "../fetch-agent"; vi.mock("undici", () => { return { diff --git a/packages/common/src/theme.ts b/packages/common/src/theme.ts new file mode 100644 index 000000000..413b1eee3 --- /dev/null +++ b/packages/common/src/theme.ts @@ -0,0 +1,5 @@ +import type { DefaultMantineColor, MantineColorShade } from "@mantine/core"; +import { DEFAULT_THEME } from "@mantine/core"; + +export const getMantineColor = (color: DefaultMantineColor, shade: MantineColorShade) => + DEFAULT_THEME.colors[color]?.[shade] ?? "#fff"; diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts index be56092f5..e6b0621ff 100644 --- a/packages/common/src/types.ts +++ b/packages/common/src/types.ts @@ -1,3 +1,5 @@ +import type { z } from "zod"; + export type MaybePromise = T | Promise; export type AtLeastOneOf = [T, ...T[]]; @@ -11,3 +13,16 @@ export type RemoveReadonly = { }; export type MaybeArray = T | T[]; +export type Inverse = { + [Key in keyof T as T[Key]]: Key; +}; + +type Invertible = Record; + +export type inferSearchParamsFromSchema = inferSearchParamsFromSchemaInner< + z.infer +>; + +type inferSearchParamsFromSchemaInner> = Partial<{ + [K in keyof TSchema]: Exclude extends unknown[] ? string[] : string; +}>; diff --git a/packages/common/src/url.ts b/packages/common/src/url.ts index aa15066f6..9e974a73e 100644 --- a/packages/common/src/url.ts +++ b/packages/common/src/url.ts @@ -4,8 +4,16 @@ export const removeTrailingSlash = (path: string) => { return path.at(-1) === "/" ? path.substring(0, path.length - 1) : path; }; -export const extractBaseUrlFromHeaders = (headers: ReadonlyHeaders): `${string}://${string}` => { - let protocol = headers.get("x-forwarded-proto") ?? "http"; +export const extractBaseUrlFromHeaders = ( + headers: ReadonlyHeaders, + fallbackProtocol: "http" | "https" = "http", +): `${string}://${string}` => { + let protocol = headers.get("x-forwarded-proto"); + + // If the protocol is not set or an empty string + if (!protocol) { + protocol = fallbackProtocol; + } // @see https://support.glitch.com/t/x-forwarded-proto-contains-multiple-protocols/17219 if (protocol.includes(",")) { diff --git a/packages/common/src/user-agent.ts b/packages/common/src/user-agent.ts new file mode 100644 index 000000000..b4a90dfb3 --- /dev/null +++ b/packages/common/src/user-agent.ts @@ -0,0 +1,11 @@ +import { userAgent as userAgentNextServer } from "next/server"; + +import type { Modify } from "./types"; + +export const userAgent = (headers: Headers) => { + return userAgentNextServer({ headers }) as Omit, "device"> & { + device: Modify["device"], { type: DeviceType }>; + }; +}; + +export type DeviceType = "console" | "mobile" | "tablet" | "smarttv" | "wearable" | "embedded" | undefined; diff --git a/packages/cron-job-runner/package.json b/packages/cron-job-runner/package.json index e3b418702..b86fcf21d 100644 --- a/packages/cron-job-runner/package.json +++ b/packages/cron-job-runner/package.json @@ -30,7 +30,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/cron-job-status/package.json b/packages/cron-job-status/package.json index f495ce6ef..2b84ecdc2 100644 --- a/packages/cron-job-status/package.json +++ b/packages/cron-job-status/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/cron-jobs-core/package.json b/packages/cron-jobs-core/package.json index 497521fe7..d9286fcb0 100644 --- a/packages/cron-jobs-core/package.json +++ b/packages/cron-jobs-core/package.json @@ -32,7 +32,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/node-cron": "^3.0.11", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/cron-jobs/package.json b/packages/cron-jobs/package.json index 1abaf0c1b..217ff58e5 100644 --- a/packages/cron-jobs/package.json +++ b/packages/cron-jobs/package.json @@ -38,13 +38,14 @@ "@homarr/request-handler": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", - "@homarr/validation": "workspace:^0.1.0" + "@homarr/validation": "workspace:^0.1.0", + "semver-parser": "^4.1.7" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/cron-jobs/src/index.ts b/packages/cron-jobs/src/index.ts index cf4132911..50dc00702 100644 --- a/packages/cron-jobs/src/index.ts +++ b/packages/cron-jobs/src/index.ts @@ -8,10 +8,13 @@ import { indexerManagerJob } from "./jobs/integrations/indexer-manager"; import { mediaOrganizerJob } from "./jobs/integrations/media-organizer"; import { mediaRequestListJob, mediaRequestStatsJob } from "./jobs/integrations/media-requests"; import { mediaServerJob } from "./jobs/integrations/media-server"; +import { mediaTranscodingJob } from "./jobs/integrations/media-transcoding"; +import { minecraftServerStatusJob } from "./jobs/minecraft-server-status"; import { pingJob } from "./jobs/ping"; import type { RssFeed } from "./jobs/rss-feeds"; import { rssFeedsJob } from "./jobs/rss-feeds"; import { sessionCleanupJob } from "./jobs/session-cleanup"; +import { updateCheckerJob } from "./jobs/update-checker"; import { createCronJobGroup } from "./lib"; export const jobGroup = createCronJobGroup({ @@ -29,6 +32,9 @@ export const jobGroup = createCronJobGroup({ indexerManager: indexerManagerJob, healthMonitoring: healthMonitoringJob, sessionCleanup: sessionCleanupJob, + updateChecker: updateCheckerJob, + mediaTranscoding: mediaTranscodingJob, + minecraftServerStatus: minecraftServerStatusJob, }); export type JobGroupKeys = ReturnType<(typeof jobGroup)["getKeys"]>[number]; diff --git a/packages/cron-jobs/src/jobs/icons-updater.ts b/packages/cron-jobs/src/jobs/icons-updater.ts index 9c4aca75d..d278e7b87 100644 --- a/packages/cron-jobs/src/jobs/icons-updater.ts +++ b/packages/cron-jobs/src/jobs/icons-updater.ts @@ -1,9 +1,9 @@ import { splitToNChunks, Stopwatch } from "@homarr/common"; import { EVERY_WEEK } from "@homarr/cron-jobs-core/expressions"; import type { InferInsertModel } from "@homarr/db"; -import { db, inArray } from "@homarr/db"; +import { db, handleTransactionsAsync, inArray, sql } from "@homarr/db"; import { createId } from "@homarr/db/client"; -import { iconRepositories, icons } from "@homarr/db/schema/sqlite"; +import { iconRepositories, icons } from "@homarr/db/schema"; import { fetchIconsAsync } from "@homarr/icons"; import { logger } from "@homarr/log"; @@ -22,13 +22,13 @@ export const iconsUpdaterJob = createCronJob("iconsUpdater", EVERY_WEEK, { `Successfully fetched ${countIcons} icons from ${repositoryIconGroups.length} repositories within ${stopWatch.getElapsedInHumanWords()}`, ); - const databaseIconGroups = await db.query.iconRepositories.findMany({ + const databaseIconRepositories = await db.query.iconRepositories.findMany({ with: { icons: true, }, }); - const skippedChecksums: string[] = []; + const skippedChecksums: `${string}.${string}`[] = []; let countDeleted = 0; let countInserted = 0; @@ -43,18 +43,24 @@ export const iconsUpdaterJob = createCronJob("iconsUpdater", EVERY_WEEK, { continue; } - const repositoryInDb = databaseIconGroups.find((dbIconGroup) => dbIconGroup.slug === repositoryIconGroup.slug); - const repositoryIconGroupId: string = repositoryInDb?.id ?? createId(); + const repositoryInDb = databaseIconRepositories.find( + (dbIconGroup) => dbIconGroup.slug === repositoryIconGroup.slug, + ); + const iconRepositoryId: string = repositoryInDb?.id ?? createId(); if (!repositoryInDb?.id) { newIconRepositories.push({ - id: repositoryIconGroupId, + id: iconRepositoryId, slug: repositoryIconGroup.slug, }); } for (const icon of repositoryIconGroup.icons) { - if (databaseIconGroups.flatMap((group) => group.icons).some((dbIcon) => dbIcon.checksum === icon.checksum)) { - skippedChecksums.push(icon.checksum); + if ( + databaseIconRepositories + .flatMap((repository) => repository.icons) + .some((dbIcon) => dbIcon.checksum === icon.checksum && dbIcon.iconRepositoryId === iconRepositoryId) + ) { + skippedChecksums.push(`${iconRepositoryId}.${icon.checksum}`); continue; } @@ -63,37 +69,95 @@ export const iconsUpdaterJob = createCronJob("iconsUpdater", EVERY_WEEK, { checksum: icon.checksum, name: icon.fileNameWithExtension, url: icon.imageUrl, - iconRepositoryId: repositoryIconGroupId, + iconRepositoryId, }); countInserted++; } } - const deadIcons = databaseIconGroups - .flatMap((group) => group.icons) - .filter((icon) => !skippedChecksums.includes(icon.checksum)); + const deadIcons = databaseIconRepositories + .flatMap((repository) => repository.icons) + .filter((icon) => !skippedChecksums.includes(`${icon.iconRepositoryId}.${icon.checksum}`)); - await db.transaction(async (transaction) => { - if (newIconRepositories.length >= 1) { - await transaction.insert(iconRepositories).values(newIconRepositories); - } + const deadIconRepositories = databaseIconRepositories.filter( + (iconRepository) => !repositoryIconGroups.some((group) => group.slug === iconRepository.slug), + ); - if (newIcons.length >= 1) { - // We only insert 5000 icons at a time to avoid SQLite limitations - for (const chunck of splitToNChunks(newIcons, Math.ceil(newIcons.length / 5000))) { - await transaction.insert(icons).values(chunck); - } - } - if (deadIcons.length >= 1) { - await transaction.delete(icons).where( - inArray( - icons.checksum, - deadIcons.map((icon) => icon.checksum), - ), - ); - } + await handleTransactionsAsync(db, { + async handleAsync(db, schema) { + await db.transaction(async (transaction) => { + if (newIconRepositories.length >= 1) { + await transaction.insert(schema.iconRepositories).values(newIconRepositories); + } - countDeleted += deadIcons.length; + if (newIcons.length >= 1) { + // We only insert 5000 icons at a time to avoid SQLite limitations + for (const chunck of splitToNChunks(newIcons, Math.ceil(newIcons.length / 5000))) { + await transaction.insert(schema.icons).values(chunck); + } + } + if (deadIcons.length >= 1) { + await transaction.delete(schema.icons).where( + inArray( + // Combine iconRepositoryId and checksum to allow same icons on different repositories + sql`concat(${icons.iconRepositoryId}, '.', ${icons.checksum})`, + deadIcons.map((icon) => `${icon.iconRepositoryId}.${icon.checksum}`), + ), + ); + } + + if (deadIconRepositories.length >= 1) { + await transaction.delete(schema.iconRepositories).where( + inArray( + iconRepositories.id, + deadIconRepositories.map((iconRepository) => iconRepository.id), + ), + ); + } + + countDeleted += deadIcons.length; + }); + }, + handleSync() { + db.transaction((transaction) => { + if (newIconRepositories.length >= 1) { + transaction.insert(iconRepositories).values(newIconRepositories).run(); + } + + if (newIcons.length >= 1) { + // We only insert 5000 icons at a time to avoid SQLite limitations + for (const chunck of splitToNChunks(newIcons, Math.ceil(newIcons.length / 5000))) { + transaction.insert(icons).values(chunck).run(); + } + } + if (deadIcons.length >= 1) { + transaction + .delete(icons) + .where( + inArray( + // Combine iconRepositoryId and checksum to allow same icons on different repositories + sql`concat(${icons.iconRepositoryId}, '.', ${icons.checksum})`, + deadIcons.map((icon) => `${icon.iconRepositoryId}.${icon.checksum}`), + ), + ) + .run(); + } + + if (deadIconRepositories.length >= 1) { + transaction + .delete(iconRepositories) + .where( + inArray( + iconRepositories.id, + deadIconRepositories.map((iconRepository) => iconRepository.id), + ), + ) + .run(); + } + + countDeleted += deadIcons.length; + }); + }, }); logger.info(`Updated database within ${stopWatch.getElapsedInHumanWords()} (-${countDeleted}, +${countInserted})`); diff --git a/packages/cron-jobs/src/jobs/integrations/health-monitoring.ts b/packages/cron-jobs/src/jobs/integrations/health-monitoring.ts index 50c80ce84..6e87a57fb 100644 --- a/packages/cron-jobs/src/jobs/integrations/health-monitoring.ts +++ b/packages/cron-jobs/src/jobs/integrations/health-monitoring.ts @@ -1,14 +1,23 @@ import { EVERY_5_SECONDS } from "@homarr/cron-jobs-core/expressions"; -import { systemInfoRequestHandler } from "@homarr/request-handler/health-monitoring"; +import { clusterInfoRequestHandler, systemInfoRequestHandler } from "@homarr/request-handler/health-monitoring"; import { createRequestIntegrationJobHandler } from "@homarr/request-handler/lib/cached-request-integration-job-handler"; import { createCronJob } from "../../lib"; export const healthMonitoringJob = createCronJob("healthMonitoring", EVERY_5_SECONDS).withCallback( - createRequestIntegrationJobHandler(systemInfoRequestHandler.handler, { - widgetKinds: ["healthMonitoring"], - getInput: { - healthMonitoring: () => ({}), + createRequestIntegrationJobHandler( + (integration, itemOptions: Record) => { + const { kind } = integration; + if (kind !== "proxmox") { + return systemInfoRequestHandler.handler({ ...integration, kind }, itemOptions); + } + return clusterInfoRequestHandler.handler({ ...integration, kind }, itemOptions); }, - }), + { + widgetKinds: ["healthMonitoring"], + getInput: { + healthMonitoring: () => ({}), + }, + }, + ), ); diff --git a/packages/cron-jobs/src/jobs/integrations/media-transcoding.ts b/packages/cron-jobs/src/jobs/integrations/media-transcoding.ts new file mode 100644 index 000000000..c039dc250 --- /dev/null +++ b/packages/cron-jobs/src/jobs/integrations/media-transcoding.ts @@ -0,0 +1,14 @@ +import { EVERY_5_MINUTES } from "@homarr/cron-jobs-core/expressions"; +import { createRequestIntegrationJobHandler } from "@homarr/request-handler/lib/cached-request-integration-job-handler"; +import { mediaTranscodingRequestHandler } from "@homarr/request-handler/media-transcoding"; + +import { createCronJob } from "../../lib"; + +export const mediaTranscodingJob = createCronJob("mediaTranscoding", EVERY_5_MINUTES).withCallback( + createRequestIntegrationJobHandler(mediaTranscodingRequestHandler.handler, { + widgetKinds: ["mediaTranscoding"], + getInput: { + mediaTranscoding: () => ({ pageOffset: 0, pageSize: 10 }), + }, + }), +); diff --git a/packages/cron-jobs/src/jobs/minecraft-server-status.ts b/packages/cron-jobs/src/jobs/minecraft-server-status.ts new file mode 100644 index 000000000..e6c084702 --- /dev/null +++ b/packages/cron-jobs/src/jobs/minecraft-server-status.ts @@ -0,0 +1,25 @@ +import SuperJSON from "superjson"; + +import { EVERY_5_MINUTES } from "@homarr/cron-jobs-core/expressions"; +import { db, eq } from "@homarr/db"; +import { items } from "@homarr/db/schema"; +import { minecraftServerStatusRequestHandler } from "@homarr/request-handler/minecraft-server-status"; + +import type { WidgetComponentProps } from "../../../widgets/src"; +import { createCronJob } from "../lib"; + +export const minecraftServerStatusJob = createCronJob("minecraftServerStatus", EVERY_5_MINUTES).withCallback( + async () => { + const dbItems = await db.query.items.findMany({ + where: eq(items.kind, "minecraftServerStatus"), + }); + + await Promise.allSettled( + dbItems.map(async (item) => { + const options = SuperJSON.parse["options"]>(item.options); + const innerHandler = minecraftServerStatusRequestHandler.handler(options); + await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: true }); + }), + ); + }, +); diff --git a/packages/cron-jobs/src/jobs/rss-feeds.ts b/packages/cron-jobs/src/jobs/rss-feeds.ts index 5c468520d..4c7f2d720 100644 --- a/packages/cron-jobs/src/jobs/rss-feeds.ts +++ b/packages/cron-jobs/src/jobs/rss-feeds.ts @@ -5,7 +5,7 @@ import SuperJSON from "superjson"; import type { Modify } from "@homarr/common/types"; import { EVERY_5_MINUTES } from "@homarr/cron-jobs-core/expressions"; import { db, eq } from "@homarr/db"; -import { items } from "@homarr/db/schema/sqlite"; +import { items } from "@homarr/db/schema"; import { logger } from "@homarr/log"; import { createItemChannel } from "@homarr/redis"; import { z } from "@homarr/validation"; diff --git a/packages/cron-jobs/src/jobs/session-cleanup.ts b/packages/cron-jobs/src/jobs/session-cleanup.ts index f9d382ad5..72f6c88fe 100644 --- a/packages/cron-jobs/src/jobs/session-cleanup.ts +++ b/packages/cron-jobs/src/jobs/session-cleanup.ts @@ -1,7 +1,7 @@ -import { env } from "@homarr/auth/env.mjs"; +import { env } from "@homarr/auth/env"; import { NEVER } from "@homarr/cron-jobs-core/expressions"; import { db, eq, inArray } from "@homarr/db"; -import { sessions, users } from "@homarr/db/schema/sqlite"; +import { sessions, users } from "@homarr/db/schema"; import { supportedAuthProviders } from "@homarr/definitions"; import { logger } from "@homarr/log"; diff --git a/packages/cron-jobs/src/jobs/update-checker.ts b/packages/cron-jobs/src/jobs/update-checker.ts new file mode 100644 index 000000000..b985485ab --- /dev/null +++ b/packages/cron-jobs/src/jobs/update-checker.ts @@ -0,0 +1,13 @@ +import { EVERY_HOUR } from "@homarr/cron-jobs-core/expressions"; +import { updateCheckerRequestHandler } from "@homarr/request-handler/update-checker"; + +import { createCronJob } from "../lib"; + +export const updateCheckerJob = createCronJob("updateChecker", EVERY_HOUR, { + runOnStart: true, +}).withCallback(async () => { + const handler = updateCheckerRequestHandler.handler({}); + await handler.getCachedOrUpdatedDataAsync({ + forceUpdate: true, + }); +}); diff --git a/packages/db/configs/mysql.config.ts b/packages/db/configs/mysql.config.ts index 95d0ab936..1eb3aa943 100644 --- a/packages/db/configs/mysql.config.ts +++ b/packages/db/configs/mysql.config.ts @@ -1,19 +1,19 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import * as dotenv from "dotenv"; import type { Config } from "drizzle-kit"; -dotenv.config({ path: "../../.env" }); +import { env } from "../env"; export default { dialect: "mysql", schema: "./schema", casing: "snake_case", - dbCredentials: { - host: process.env.DB_HOST!, - user: process.env.DB_USER!, - password: process.env.DB_PASSWORD!, - database: process.env.DB_NAME!, - port: parseInt(process.env.DB_PORT!), - }, + dbCredentials: env.DB_URL + ? { url: env.DB_URL } + : { + host: env.DB_HOST, + user: env.DB_USER, + password: env.DB_PASSWORD, + database: env.DB_NAME, + port: env.DB_PORT, + }, out: "./migrations/mysql", } satisfies Config; diff --git a/packages/db/configs/sqlite.config.ts b/packages/db/configs/sqlite.config.ts index 8e71be989..6b38860f2 100644 --- a/packages/db/configs/sqlite.config.ts +++ b/packages/db/configs/sqlite.config.ts @@ -1,13 +1,11 @@ -import * as dotenv from "dotenv"; import type { Config } from "drizzle-kit"; -dotenv.config({ path: "../../.env" }); +import { env } from "../env"; export default { dialect: "sqlite", schema: "./schema", casing: "snake_case", - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - dbCredentials: { url: process.env.DB_URL! }, + dbCredentials: { url: env.DB_URL }, out: "./migrations/sqlite", } satisfies Config; diff --git a/packages/db/driver.ts b/packages/db/driver.ts index 9eac1531d..2dce7f4a0 100644 --- a/packages/db/driver.ts +++ b/packages/db/driver.ts @@ -2,20 +2,23 @@ import Database from "better-sqlite3"; import type { Logger } from "drizzle-orm"; import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3"; import { drizzle as drizzleSqlite } from "drizzle-orm/better-sqlite3"; +import type { MySql2Database } from "drizzle-orm/mysql2"; import { drizzle as drizzleMysql } from "drizzle-orm/mysql2"; import mysql from "mysql2"; import { logger } from "@homarr/log"; +import { env } from "./env"; import * as mysqlSchema from "./schema/mysql"; import * as sqliteSchema from "./schema/sqlite"; -type HomarrDatabase = BetterSQLite3Database; +export type HomarrDatabase = BetterSQLite3Database; +export type HomarrDatabaseMysql = MySql2Database; const init = () => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!connection) { - switch (process.env.DB_DRIVER) { + switch (env.DB_DRIVER) { case "mysql2": initMySQL2(); break; @@ -36,7 +39,7 @@ class WinstonDrizzleLogger implements Logger { } const initBetterSqlite = () => { - connection = new Database(process.env.DB_URL); + connection = new Database(env.DB_URL); database = drizzleSqlite(connection, { schema: sqliteSchema, logger: new WinstonDrizzleLogger(), @@ -45,16 +48,15 @@ const initBetterSqlite = () => { }; const initMySQL2 = () => { - if (!process.env.DB_HOST) { - connection = mysql.createConnection({ uri: process.env.DB_URL }); + if (!env.DB_HOST) { + connection = mysql.createConnection({ uri: env.DB_URL }); } else { connection = mysql.createConnection({ - host: process.env.DB_HOST, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - database: process.env.DB_NAME!, - port: Number(process.env.DB_PORT), - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, + host: env.DB_HOST, + database: env.DB_NAME, + port: env.DB_PORT, + user: env.DB_USER, + password: env.DB_PASSWORD, }); } diff --git a/packages/db/env.ts b/packages/db/env.ts new file mode 100644 index 000000000..4c5ae0319 --- /dev/null +++ b/packages/db/env.ts @@ -0,0 +1,61 @@ +import { createEnv } from "@t3-oss/env-nextjs"; +import { z } from "zod"; + +import { shouldSkipEnvValidation } from "@homarr/common/env-validation"; + +const drivers = { + betterSqlite3: "better-sqlite3", + mysql2: "mysql2", +} as const; + +const isDriver = (driver: (typeof drivers)[keyof typeof drivers]) => process.env.DB_DRIVER === driver; +const isUsingDbHost = Boolean(process.env.DB_HOST); +const onlyAllowUrl = isDriver(drivers.betterSqlite3); +const urlRequired = onlyAllowUrl || !isUsingDbHost; +const hostRequired = isUsingDbHost && !onlyAllowUrl; + +export const env = createEnv({ + /** + * Specify your server-side environment variables schema here. This way you can ensure the app isn't + * built with invalid env vars. + */ + server: { + DB_DRIVER: z + .union([z.literal(drivers.betterSqlite3), z.literal(drivers.mysql2)], { + message: `Invalid database driver, supported are ${Object.keys(drivers).join(", ")}`, + }) + .default(drivers.betterSqlite3), + ...(urlRequired + ? { + DB_URL: z.string(), + } + : {}), + ...(hostRequired + ? { + DB_HOST: z.string(), + DB_PORT: z + .string() + .regex(/\d+/) + .transform(Number) + .refine((number) => number >= 1) + .default("3306"), + DB_USER: z.string(), + DB_PASSWORD: z.string(), + DB_NAME: z.string(), + } + : {}), + }, + /** + * Destructure all variables from `process.env` to make sure they aren't tree-shaken away. + */ + runtimeEnv: { + DB_DRIVER: process.env.DB_DRIVER, + DB_URL: process.env.DB_URL, + DB_HOST: process.env.DB_HOST, + DB_USER: process.env.DB_USER, + DB_PASSWORD: process.env.DB_PASSWORD, + DB_NAME: process.env.DB_NAME, + DB_PORT: process.env.DB_PORT, + }, + skipValidation: shouldSkipEnvValidation(), +}); diff --git a/packages/db/index.ts b/packages/db/index.ts index beec11606..ac54017c0 100644 --- a/packages/db/index.ts +++ b/packages/db/index.ts @@ -1,15 +1,13 @@ import Database from "better-sqlite3"; import { database } from "./driver"; -import * as sqliteSchema from "./schema/sqlite"; - -// Export only the types from the sqlite schema as we're using that. -export const schema = sqliteSchema; export * from "drizzle-orm"; export const db = database; export type Database = typeof db; +export type { HomarrDatabaseMysql } from "./driver"; export { createId } from "@paralleldrive/cuid2"; +export { handleDiffrentDbDriverOperationsAsync as handleTransactionsAsync } from "./transactions"; diff --git a/packages/db/migrations/mysql/0017_tired_penance.sql b/packages/db/migrations/mysql/0017_tired_penance.sql new file mode 100644 index 000000000..e27e77f30 --- /dev/null +++ b/packages/db/migrations/mysql/0017_tired_penance.sql @@ -0,0 +1,6 @@ +CREATE TABLE `onboarding` ( + `id` varchar(64) NOT NULL, + `step` varchar(64) NOT NULL, + `previous_step` varchar(64), + CONSTRAINT `onboarding_id` PRIMARY KEY(`id`) +); diff --git a/packages/db/migrations/mysql/0018_mighty_shaman.sql b/packages/db/migrations/mysql/0018_mighty_shaman.sql new file mode 100644 index 000000000..e31e98b72 --- /dev/null +++ b/packages/db/migrations/mysql/0018_mighty_shaman.sql @@ -0,0 +1 @@ +ALTER TABLE `search_engine` ADD CONSTRAINT `search_engine_short_unique` UNIQUE(`short`); \ No newline at end of file diff --git a/packages/db/migrations/mysql/0019_crazy_marvel_zombies.sql b/packages/db/migrations/mysql/0019_crazy_marvel_zombies.sql new file mode 100644 index 000000000..16985974f --- /dev/null +++ b/packages/db/migrations/mysql/0019_crazy_marvel_zombies.sql @@ -0,0 +1,2 @@ +ALTER TABLE `user` ADD `default_search_engine_id` varchar(64);--> statement-breakpoint +ALTER TABLE `user` ADD CONSTRAINT `user_default_search_engine_id_search_engine_id_fk` FOREIGN KEY (`default_search_engine_id`) REFERENCES `search_engine`(`id`) ON DELETE set null ON UPDATE no action; \ No newline at end of file diff --git a/packages/db/migrations/mysql/0020_salty_doorman.sql b/packages/db/migrations/mysql/0020_salty_doorman.sql new file mode 100644 index 000000000..5a92f9205 --- /dev/null +++ b/packages/db/migrations/mysql/0020_salty_doorman.sql @@ -0,0 +1,2 @@ +ALTER TABLE `user` ADD `mobile_home_board_id` varchar(64);--> statement-breakpoint +ALTER TABLE `user` ADD CONSTRAINT `user_mobile_home_board_id_board_id_fk` FOREIGN KEY (`mobile_home_board_id`) REFERENCES `board`(`id`) ON DELETE set null ON UPDATE no action; \ No newline at end of file diff --git a/packages/db/migrations/mysql/meta/0017_snapshot.json b/packages/db/migrations/mysql/meta/0017_snapshot.json new file mode 100644 index 000000000..fc3653698 --- /dev/null +++ b/packages/db/migrations/mysql/meta/0017_snapshot.json @@ -0,0 +1,1663 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "a47534f2-313d-4234-a5d3-0b48da85f84c", + "prevId": "50b295e1-1802-477c-9ee1-b2cad1e9f5bb", + "tables": { + "account": { + "name": "account", + "columns": { + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_account_id": { + "name": "provider_account_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_provider_account_id_pk": { + "name": "account_provider_provider_account_id_pk", + "columns": ["provider", "provider_account_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_user_id_user_id_fk": { + "name": "apiKey_user_id_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "apiKey_id": { + "name": "apiKey_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "app_id": { + "name": "app_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "name": "boardGroupPermission_board_id_group_id_permission_pk", + "columns": ["board_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "name": "boardUserPermission_board_id_user_id_permission_pk", + "columns": ["board_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('fixed')" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('no-repeat')" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('cover')" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fa5252')" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fd7e14')" + }, + "opacity": { + "name": "opacity", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": {}, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "board_id": { + "name": "board_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"] + } + }, + "checkConstraint": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_group_id_group_id_fk": { + "name": "groupMember_group_id_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_user_id_user_id_fk": { + "name": "groupMember_user_id_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_group_id_user_id_pk": { + "name": "groupMember_group_id_user_id_pk", + "columns": ["group_id", "user_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_group_id_group_id_fk": { + "name": "groupPermission_group_id_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "group_id": { + "name": "group_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "group_name_unique": { + "name": "group_name_unique", + "columns": ["name"] + } + }, + "checkConstraint": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(150)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "iconRepository_id": { + "name": "iconRepository_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "icon": { + "name": "icon", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(250)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_repository_id": { + "name": "icon_repository_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_icon_repository_id_iconRepository_id_fk": { + "name": "icon_icon_repository_id_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "icon_id": { + "name": "icon_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_group_permission__pk": { + "name": "integration_group_permission__pk", + "columns": ["integration_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "name": "integration_item_item_id_integration_id_pk", + "columns": ["item_id", "integration_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "name": "integrationSecret_integration_id_kind_pk", + "columns": ["integration_id", "kind"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "name": "integrationUserPermission_integration_id_user_id_permission_pk", + "columns": ["integration_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "integration_id": { + "name": "integration_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "invite_id": { + "name": "invite_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_id": { + "name": "item_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "media": { + "name": "media", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "BLOB", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "media_creator_id_user_id_fk": { + "name": "media_creator_id_user_id_fk", + "tableFrom": "media", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "media_id": { + "name": "media_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "onboarding": { + "name": "onboarding", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "step": { + "name": "step", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "previous_step": { + "name": "previous_step", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "onboarding_id": { + "name": "onboarding_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "varchar(8)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'generic'" + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "search_engine_integration_id_integration_id_fk": { + "name": "search_engine_integration_id_integration_id_fk", + "tableFrom": "search_engine", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "search_engine_id": { + "name": "search_engine_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_id": { + "name": "section_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "setting_key": { + "name": "setting_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "serverSetting_setting_key": { + "name": "serverSetting_setting_key", + "columns": ["setting_key"] + } + }, + "uniqueConstraints": { + "serverSetting_settingKey_unique": { + "name": "serverSetting_settingKey_unique", + "columns": ["setting_key"] + } + }, + "checkConstraint": {} + }, + "session": { + "name": "session", + "columns": { + "session_token": { + "name": "session_token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "session_session_token": { + "name": "session_session_token", + "columns": ["session_token"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "home_board_id": { + "name": "home_board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color_scheme": { + "name": "color_scheme", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "first_day_of_week": { + "name": "first_day_of_week", + "type": "tinyint", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "ping_icons_enabled": { + "name": "ping_icons_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_home_board_id_board_id_fk": { + "name": "user_home_board_id_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_id": { + "name": "user_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": ["identifier", "token"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/migrations/mysql/meta/0018_snapshot.json b/packages/db/migrations/mysql/meta/0018_snapshot.json new file mode 100644 index 000000000..bf8436546 --- /dev/null +++ b/packages/db/migrations/mysql/meta/0018_snapshot.json @@ -0,0 +1,1668 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "028a5116-ccea-4095-9434-7ac3bf726c9a", + "prevId": "a47534f2-313d-4234-a5d3-0b48da85f84c", + "tables": { + "account": { + "name": "account", + "columns": { + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_account_id": { + "name": "provider_account_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_provider_account_id_pk": { + "name": "account_provider_provider_account_id_pk", + "columns": ["provider", "provider_account_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_user_id_user_id_fk": { + "name": "apiKey_user_id_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "apiKey_id": { + "name": "apiKey_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "app_id": { + "name": "app_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "name": "boardGroupPermission_board_id_group_id_permission_pk", + "columns": ["board_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "name": "boardUserPermission_board_id_user_id_permission_pk", + "columns": ["board_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('fixed')" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('no-repeat')" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('cover')" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fa5252')" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fd7e14')" + }, + "opacity": { + "name": "opacity", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": {}, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "board_id": { + "name": "board_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"] + } + }, + "checkConstraint": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_group_id_group_id_fk": { + "name": "groupMember_group_id_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_user_id_user_id_fk": { + "name": "groupMember_user_id_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_group_id_user_id_pk": { + "name": "groupMember_group_id_user_id_pk", + "columns": ["group_id", "user_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_group_id_group_id_fk": { + "name": "groupPermission_group_id_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "group_id": { + "name": "group_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "group_name_unique": { + "name": "group_name_unique", + "columns": ["name"] + } + }, + "checkConstraint": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(150)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "iconRepository_id": { + "name": "iconRepository_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "icon": { + "name": "icon", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(250)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_repository_id": { + "name": "icon_repository_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_icon_repository_id_iconRepository_id_fk": { + "name": "icon_icon_repository_id_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "icon_id": { + "name": "icon_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_group_permission__pk": { + "name": "integration_group_permission__pk", + "columns": ["integration_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "name": "integration_item_item_id_integration_id_pk", + "columns": ["item_id", "integration_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "name": "integrationSecret_integration_id_kind_pk", + "columns": ["integration_id", "kind"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "name": "integrationUserPermission_integration_id_user_id_permission_pk", + "columns": ["integration_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "integration_id": { + "name": "integration_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "invite_id": { + "name": "invite_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_id": { + "name": "item_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "media": { + "name": "media", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "BLOB", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "media_creator_id_user_id_fk": { + "name": "media_creator_id_user_id_fk", + "tableFrom": "media", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "media_id": { + "name": "media_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "onboarding": { + "name": "onboarding", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "step": { + "name": "step", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "previous_step": { + "name": "previous_step", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "onboarding_id": { + "name": "onboarding_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "varchar(8)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'generic'" + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "search_engine_integration_id_integration_id_fk": { + "name": "search_engine_integration_id_integration_id_fk", + "tableFrom": "search_engine", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "search_engine_id": { + "name": "search_engine_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "search_engine_short_unique": { + "name": "search_engine_short_unique", + "columns": ["short"] + } + }, + "checkConstraint": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_id": { + "name": "section_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "setting_key": { + "name": "setting_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "serverSetting_setting_key": { + "name": "serverSetting_setting_key", + "columns": ["setting_key"] + } + }, + "uniqueConstraints": { + "serverSetting_settingKey_unique": { + "name": "serverSetting_settingKey_unique", + "columns": ["setting_key"] + } + }, + "checkConstraint": {} + }, + "session": { + "name": "session", + "columns": { + "session_token": { + "name": "session_token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "session_session_token": { + "name": "session_session_token", + "columns": ["session_token"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "home_board_id": { + "name": "home_board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color_scheme": { + "name": "color_scheme", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "first_day_of_week": { + "name": "first_day_of_week", + "type": "tinyint", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "ping_icons_enabled": { + "name": "ping_icons_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_home_board_id_board_id_fk": { + "name": "user_home_board_id_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_id": { + "name": "user_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": ["identifier", "token"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/migrations/mysql/meta/0019_snapshot.json b/packages/db/migrations/mysql/meta/0019_snapshot.json new file mode 100644 index 000000000..91325ec34 --- /dev/null +++ b/packages/db/migrations/mysql/meta/0019_snapshot.json @@ -0,0 +1,1684 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "0587ca9d-bbfc-4241-ba82-e52a7664a1dc", + "prevId": "028a5116-ccea-4095-9434-7ac3bf726c9a", + "tables": { + "account": { + "name": "account", + "columns": { + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_account_id": { + "name": "provider_account_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_provider_account_id_pk": { + "name": "account_provider_provider_account_id_pk", + "columns": ["provider", "provider_account_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_user_id_user_id_fk": { + "name": "apiKey_user_id_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "apiKey_id": { + "name": "apiKey_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "app_id": { + "name": "app_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "name": "boardGroupPermission_board_id_group_id_permission_pk", + "columns": ["board_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "name": "boardUserPermission_board_id_user_id_permission_pk", + "columns": ["board_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('fixed')" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('no-repeat')" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('cover')" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fa5252')" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fd7e14')" + }, + "opacity": { + "name": "opacity", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": {}, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "board_id": { + "name": "board_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"] + } + }, + "checkConstraint": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_group_id_group_id_fk": { + "name": "groupMember_group_id_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_user_id_user_id_fk": { + "name": "groupMember_user_id_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_group_id_user_id_pk": { + "name": "groupMember_group_id_user_id_pk", + "columns": ["group_id", "user_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_group_id_group_id_fk": { + "name": "groupPermission_group_id_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "group_id": { + "name": "group_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "group_name_unique": { + "name": "group_name_unique", + "columns": ["name"] + } + }, + "checkConstraint": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(150)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "iconRepository_id": { + "name": "iconRepository_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "icon": { + "name": "icon", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(250)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_repository_id": { + "name": "icon_repository_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_icon_repository_id_iconRepository_id_fk": { + "name": "icon_icon_repository_id_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "icon_id": { + "name": "icon_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_group_permission__pk": { + "name": "integration_group_permission__pk", + "columns": ["integration_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "name": "integration_item_item_id_integration_id_pk", + "columns": ["item_id", "integration_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "name": "integrationSecret_integration_id_kind_pk", + "columns": ["integration_id", "kind"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "name": "integrationUserPermission_integration_id_user_id_permission_pk", + "columns": ["integration_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "integration_id": { + "name": "integration_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "invite_id": { + "name": "invite_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_id": { + "name": "item_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "media": { + "name": "media", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "BLOB", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "media_creator_id_user_id_fk": { + "name": "media_creator_id_user_id_fk", + "tableFrom": "media", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "media_id": { + "name": "media_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "onboarding": { + "name": "onboarding", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "step": { + "name": "step", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "previous_step": { + "name": "previous_step", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "onboarding_id": { + "name": "onboarding_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "varchar(8)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'generic'" + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "search_engine_integration_id_integration_id_fk": { + "name": "search_engine_integration_id_integration_id_fk", + "tableFrom": "search_engine", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "search_engine_id": { + "name": "search_engine_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "search_engine_short_unique": { + "name": "search_engine_short_unique", + "columns": ["short"] + } + }, + "checkConstraint": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_id": { + "name": "section_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "setting_key": { + "name": "setting_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "serverSetting_setting_key": { + "name": "serverSetting_setting_key", + "columns": ["setting_key"] + } + }, + "uniqueConstraints": { + "serverSetting_settingKey_unique": { + "name": "serverSetting_settingKey_unique", + "columns": ["setting_key"] + } + }, + "checkConstraint": {} + }, + "session": { + "name": "session", + "columns": { + "session_token": { + "name": "session_token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "session_session_token": { + "name": "session_session_token", + "columns": ["session_token"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "home_board_id": { + "name": "home_board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "default_search_engine_id": { + "name": "default_search_engine_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color_scheme": { + "name": "color_scheme", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "first_day_of_week": { + "name": "first_day_of_week", + "type": "tinyint", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "ping_icons_enabled": { + "name": "ping_icons_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_home_board_id_board_id_fk": { + "name": "user_home_board_id_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "user_default_search_engine_id_search_engine_id_fk": { + "name": "user_default_search_engine_id_search_engine_id_fk", + "tableFrom": "user", + "tableTo": "search_engine", + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_id": { + "name": "user_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": ["identifier", "token"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/migrations/mysql/meta/0020_snapshot.json b/packages/db/migrations/mysql/meta/0020_snapshot.json new file mode 100644 index 000000000..02538145b --- /dev/null +++ b/packages/db/migrations/mysql/meta/0020_snapshot.json @@ -0,0 +1,1700 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "15a80313-f75e-4d8d-b9ec-8cb1de245493", + "prevId": "0587ca9d-bbfc-4241-ba82-e52a7664a1dc", + "tables": { + "account": { + "name": "account", + "columns": { + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_account_id": { + "name": "provider_account_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_provider_account_id_pk": { + "name": "account_provider_provider_account_id_pk", + "columns": ["provider", "provider_account_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_user_id_user_id_fk": { + "name": "apiKey_user_id_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "apiKey_id": { + "name": "apiKey_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "app_id": { + "name": "app_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "name": "boardGroupPermission_board_id_group_id_permission_pk", + "columns": ["board_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "name": "boardUserPermission_board_id_user_id_permission_pk", + "columns": ["board_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('fixed')" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('no-repeat')" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('cover')" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fa5252')" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('#fd7e14')" + }, + "opacity": { + "name": "opacity", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": {}, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "board_id": { + "name": "board_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"] + } + }, + "checkConstraint": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_group_id_group_id_fk": { + "name": "groupMember_group_id_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_user_id_user_id_fk": { + "name": "groupMember_user_id_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_group_id_user_id_pk": { + "name": "groupMember_group_id_user_id_pk", + "columns": ["group_id", "user_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_group_id_group_id_fk": { + "name": "groupPermission_group_id_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "group_id": { + "name": "group_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "group_name_unique": { + "name": "group_name_unique", + "columns": ["name"] + } + }, + "checkConstraint": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "varchar(150)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "iconRepository_id": { + "name": "iconRepository_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "icon": { + "name": "icon", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(250)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_repository_id": { + "name": "icon_repository_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_icon_repository_id_iconRepository_id_fk": { + "name": "icon_icon_repository_id_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "icon_id": { + "name": "icon_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_group_permission__pk": { + "name": "integration_group_permission__pk", + "columns": ["integration_id", "group_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "name": "integration_item_item_id_integration_id_pk", + "columns": ["item_id", "integration_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "name": "integrationSecret_integration_id_kind_pk", + "columns": ["integration_id", "kind"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "name": "integrationUserPermission_integration_id_user_id_permission_pk", + "columns": ["integration_id", "user_id", "permission"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "integration_id": { + "name": "integration_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "invite_id": { + "name": "invite_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"] + } + }, + "checkConstraint": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_id": { + "name": "item_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "media": { + "name": "media", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "BLOB", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "media_creator_id_user_id_fk": { + "name": "media_creator_id_user_id_fk", + "tableFrom": "media", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "media_id": { + "name": "media_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "onboarding": { + "name": "onboarding", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "step": { + "name": "step", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "previous_step": { + "name": "previous_step", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "onboarding_id": { + "name": "onboarding_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "varchar(8)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'generic'" + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "search_engine_integration_id_integration_id_fk": { + "name": "search_engine_integration_id_integration_id_fk", + "tableFrom": "search_engine", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "search_engine_id": { + "name": "search_engine_id", + "columns": ["id"] + } + }, + "uniqueConstraints": { + "search_engine_short_unique": { + "name": "search_engine_short_unique", + "columns": ["short"] + } + }, + "checkConstraint": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_id": { + "name": "section_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "setting_key": { + "name": "setting_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "serverSetting_setting_key": { + "name": "serverSetting_setting_key", + "columns": ["setting_key"] + } + }, + "uniqueConstraints": { + "serverSetting_settingKey_unique": { + "name": "serverSetting_settingKey_unique", + "columns": ["setting_key"] + } + }, + "checkConstraint": {} + }, + "session": { + "name": "session", + "columns": { + "session_token": { + "name": "session_token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "session_session_token": { + "name": "session_session_token", + "columns": ["session_token"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "home_board_id": { + "name": "home_board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "mobile_home_board_id": { + "name": "mobile_home_board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "default_search_engine_id": { + "name": "default_search_engine_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color_scheme": { + "name": "color_scheme", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "first_day_of_week": { + "name": "first_day_of_week", + "type": "tinyint", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "ping_icons_enabled": { + "name": "ping_icons_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_home_board_id_board_id_fk": { + "name": "user_home_board_id_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "user_mobile_home_board_id_board_id_fk": { + "name": "user_mobile_home_board_id_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "user_default_search_engine_id_search_engine_id_fk": { + "name": "user_default_search_engine_id_search_engine_id_fk", + "tableFrom": "user", + "tableTo": "search_engine", + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_id": { + "name": "user_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": ["identifier", "token"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/migrations/mysql/meta/_journal.json b/packages/db/migrations/mysql/meta/_journal.json index d740783f1..0cd3cfe2a 100644 --- a/packages/db/migrations/mysql/meta/_journal.json +++ b/packages/db/migrations/mysql/meta/_journal.json @@ -120,6 +120,34 @@ "when": 1732212709518, "tag": "0016_change_all_to_snake_case", "breakpoints": true + }, + { + "idx": 17, + "version": "5", + "when": 1733777544067, + "tag": "0017_tired_penance", + "breakpoints": true + }, + { + "idx": 18, + "version": "5", + "when": 1735593853768, + "tag": "0018_mighty_shaman", + "breakpoints": true + }, + { + "idx": 19, + "version": "5", + "when": 1735651231818, + "tag": "0019_crazy_marvel_zombies", + "breakpoints": true + }, + { + "idx": 20, + "version": "5", + "when": 1736514409126, + "tag": "0020_salty_doorman", + "breakpoints": true } ] } diff --git a/packages/db/migrations/mysql/migrate.ts b/packages/db/migrations/mysql/migrate.ts index 61a2401f7..4b2616c49 100644 --- a/packages/db/migrations/mysql/migrate.ts +++ b/packages/db/migrations/mysql/migrate.ts @@ -1,9 +1,9 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { drizzle } from "drizzle-orm/mysql2"; import { migrate } from "drizzle-orm/mysql2/migrator"; import mysql from "mysql2"; import type { Database } from "../.."; +import { env } from "../../env"; import * as mysqlSchema from "../../schema/mysql"; import { seedDataAsync } from "../seed"; @@ -11,15 +11,15 @@ const migrationsFolder = process.argv[2] ?? "."; const migrateAsync = async () => { const mysql2 = mysql.createConnection( - process.env.DB_HOST - ? { - host: process.env.DB_HOST, - database: process.env.DB_NAME!, - port: Number(process.env.DB_PORT), - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - } - : { uri: process.env.DB_URL }, + env.DB_URL + ? { uri: env.DB_URL } + : { + host: env.DB_HOST, + database: env.DB_NAME, + port: env.DB_PORT, + user: env.DB_USER, + password: env.DB_PASSWORD, + }, ); const db = drizzle(mysql2, { diff --git a/packages/db/migrations/seed.ts b/packages/db/migrations/seed.ts index 79a90c45e..105147e20 100644 --- a/packages/db/migrations/seed.ts +++ b/packages/db/migrations/seed.ts @@ -6,11 +6,12 @@ import { defaultServerSettings, defaultServerSettingsKeys } from "@homarr/server import { createId, eq } from ".."; import type { Database } from ".."; +import { onboarding, serverSettings } from "../schema"; import { groups } from "../schema/mysql"; -import { serverSettings } from "../schema/sqlite"; export const seedDataAsync = async (db: Database) => { await seedEveryoneGroupAsync(db); + await seedOnboardingAsync(db); await seedServerSettingsAsync(db); }; @@ -31,6 +32,21 @@ const seedEveryoneGroupAsync = async (db: Database) => { console.log("Created group 'everyone' through seed"); }; +const seedOnboardingAsync = async (db: Database) => { + const existing = await db.query.onboarding.findFirst(); + + if (existing) { + console.log("Skipping seeding of onboarding as it already exists"); + return; + } + + await db.insert(onboarding).values({ + id: createId(), + step: "start", + }); + console.log("Created onboarding step through seed"); +}; + const seedServerSettingsAsync = async (db: Database) => { const serverSettingsData = await db.query.serverSettings.findMany(); diff --git a/packages/db/migrations/sqlite/0017_small_rumiko_fujikawa.sql b/packages/db/migrations/sqlite/0017_small_rumiko_fujikawa.sql new file mode 100644 index 000000000..c7e3aa09f --- /dev/null +++ b/packages/db/migrations/sqlite/0017_small_rumiko_fujikawa.sql @@ -0,0 +1,5 @@ +CREATE TABLE `onboarding` ( + `id` text PRIMARY KEY NOT NULL, + `step` text NOT NULL, + `previous_step` text +); diff --git a/packages/db/migrations/sqlite/0018_cheerful_tattoo.sql b/packages/db/migrations/sqlite/0018_cheerful_tattoo.sql new file mode 100644 index 000000000..11e118663 --- /dev/null +++ b/packages/db/migrations/sqlite/0018_cheerful_tattoo.sql @@ -0,0 +1 @@ +CREATE UNIQUE INDEX `search_engine_short_unique` ON `search_engine` (`short`); \ No newline at end of file diff --git a/packages/db/migrations/sqlite/0019_steady_darkhawk.sql b/packages/db/migrations/sqlite/0019_steady_darkhawk.sql new file mode 100644 index 000000000..a3da46c8d --- /dev/null +++ b/packages/db/migrations/sqlite/0019_steady_darkhawk.sql @@ -0,0 +1 @@ +ALTER TABLE `user` ADD `default_search_engine_id` text REFERENCES search_engine(id); \ No newline at end of file diff --git a/packages/db/migrations/sqlite/0020_empty_hellfire_club.sql b/packages/db/migrations/sqlite/0020_empty_hellfire_club.sql new file mode 100644 index 000000000..095f964fa --- /dev/null +++ b/packages/db/migrations/sqlite/0020_empty_hellfire_club.sql @@ -0,0 +1 @@ +ALTER TABLE `user` ADD `mobile_home_board_id` text REFERENCES board(id); \ No newline at end of file diff --git a/packages/db/migrations/sqlite/meta/0017_snapshot.json b/packages/db/migrations/sqlite/meta/0017_snapshot.json new file mode 100644 index 000000000..73cf3303b --- /dev/null +++ b/packages/db/migrations/sqlite/meta/0017_snapshot.json @@ -0,0 +1,1587 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "8946270f-5c29-4ecb-b3c9-af35b9b38f68", + "prevId": "e1f073f2-71de-489f-8268-4754a7ccff10", + "tables": { + "account": { + "name": "account", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_account_id": { + "name": "provider_account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_provider_account_id_pk": { + "columns": ["provider", "provider_account_id"], + "name": "account_provider_provider_account_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_user_id_user_id_fk": { + "name": "apiKey_user_id_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "columns": ["board_id", "group_id", "permission"], + "name": "boardGroupPermission_board_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "columns": ["board_id", "user_id", "permission"], + "name": "boardUserPermission_board_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'fixed'" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'no-repeat'" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'cover'" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fa5252'" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fd7e14'" + }, + "opacity": { + "name": "opacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_group_id_group_id_fk": { + "name": "groupMember_group_id_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_user_id_user_id_fk": { + "name": "groupMember_user_id_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_group_id_user_id_pk": { + "columns": ["group_id", "user_id"], + "name": "groupMember_group_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_group_id_group_id_fk": { + "name": "groupPermission_group_id_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "group_name_unique": { + "name": "group_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "icon": { + "name": "icon", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_repository_id": { + "name": "icon_repository_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_icon_repository_id_iconRepository_id_fk": { + "name": "icon_icon_repository_id_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationGroupPermissions_integration_id_group_id_permission_pk": { + "columns": ["integration_id", "group_id", "permission"], + "name": "integrationGroupPermissions_integration_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "columns": ["item_id", "integration_id"], + "name": "integration_item_item_id_integration_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "columns": ["integration_id", "kind"], + "name": "integrationSecret_integration_id_kind_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "columns": ["integration_id", "user_id", "permission"], + "name": "integrationUserPermission_integration_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"], + "isUnique": true + } + }, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "media": { + "name": "media", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "blob", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "media_creator_id_user_id_fk": { + "name": "media_creator_id_user_id_fk", + "tableFrom": "media", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "onboarding": { + "name": "onboarding", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "step": { + "name": "step", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "previous_step": { + "name": "previous_step", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'generic'" + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "search_engine_integration_id_integration_id_fk": { + "name": "search_engine_integration_id_integration_id_fk", + "tableFrom": "search_engine", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "setting_key": { + "name": "setting_key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": { + "serverSetting_settingKey_unique": { + "name": "serverSetting_settingKey_unique", + "columns": ["setting_key"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "session_token": { + "name": "session_token", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "home_board_id": { + "name": "home_board_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color_scheme": { + "name": "color_scheme", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "first_day_of_week": { + "name": "first_day_of_week", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "ping_icons_enabled": { + "name": "ping_icons_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_home_board_id_board_id_fk": { + "name": "user_home_board_id_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": ["identifier", "token"], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/packages/db/migrations/sqlite/meta/0018_snapshot.json b/packages/db/migrations/sqlite/meta/0018_snapshot.json new file mode 100644 index 000000000..976c4f577 --- /dev/null +++ b/packages/db/migrations/sqlite/meta/0018_snapshot.json @@ -0,0 +1,1593 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "79b4322d-1df0-4d65-afef-e9b576874eeb", + "prevId": "8946270f-5c29-4ecb-b3c9-af35b9b38f68", + "tables": { + "account": { + "name": "account", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_account_id": { + "name": "provider_account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_provider_account_id_pk": { + "columns": ["provider", "provider_account_id"], + "name": "account_provider_provider_account_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_user_id_user_id_fk": { + "name": "apiKey_user_id_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "columns": ["board_id", "group_id", "permission"], + "name": "boardGroupPermission_board_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "columns": ["board_id", "user_id", "permission"], + "name": "boardUserPermission_board_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'fixed'" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'no-repeat'" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'cover'" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fa5252'" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fd7e14'" + }, + "opacity": { + "name": "opacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_group_id_group_id_fk": { + "name": "groupMember_group_id_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_user_id_user_id_fk": { + "name": "groupMember_user_id_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_group_id_user_id_pk": { + "columns": ["group_id", "user_id"], + "name": "groupMember_group_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_group_id_group_id_fk": { + "name": "groupPermission_group_id_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "group_name_unique": { + "name": "group_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "icon": { + "name": "icon", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_repository_id": { + "name": "icon_repository_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_icon_repository_id_iconRepository_id_fk": { + "name": "icon_icon_repository_id_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationGroupPermissions_integration_id_group_id_permission_pk": { + "columns": ["integration_id", "group_id", "permission"], + "name": "integrationGroupPermissions_integration_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "columns": ["item_id", "integration_id"], + "name": "integration_item_item_id_integration_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "columns": ["integration_id", "kind"], + "name": "integrationSecret_integration_id_kind_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "columns": ["integration_id", "user_id", "permission"], + "name": "integrationUserPermission_integration_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"], + "isUnique": true + } + }, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "media": { + "name": "media", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "blob", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "media_creator_id_user_id_fk": { + "name": "media_creator_id_user_id_fk", + "tableFrom": "media", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "onboarding": { + "name": "onboarding", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "step": { + "name": "step", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "previous_step": { + "name": "previous_step", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'generic'" + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "search_engine_short_unique": { + "name": "search_engine_short_unique", + "columns": ["short"], + "isUnique": true + } + }, + "foreignKeys": { + "search_engine_integration_id_integration_id_fk": { + "name": "search_engine_integration_id_integration_id_fk", + "tableFrom": "search_engine", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "setting_key": { + "name": "setting_key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": { + "serverSetting_settingKey_unique": { + "name": "serverSetting_settingKey_unique", + "columns": ["setting_key"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "session_token": { + "name": "session_token", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "home_board_id": { + "name": "home_board_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color_scheme": { + "name": "color_scheme", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "first_day_of_week": { + "name": "first_day_of_week", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "ping_icons_enabled": { + "name": "ping_icons_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_home_board_id_board_id_fk": { + "name": "user_home_board_id_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": ["identifier", "token"], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/packages/db/migrations/sqlite/meta/0019_snapshot.json b/packages/db/migrations/sqlite/meta/0019_snapshot.json new file mode 100644 index 000000000..92fd5590b --- /dev/null +++ b/packages/db/migrations/sqlite/meta/0019_snapshot.json @@ -0,0 +1,1609 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "08cb7257-ba7e-4d4e-9fe7-85656fc115b0", + "prevId": "79b4322d-1df0-4d65-afef-e9b576874eeb", + "tables": { + "account": { + "name": "account", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_account_id": { + "name": "provider_account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_provider_account_id_pk": { + "columns": ["provider", "provider_account_id"], + "name": "account_provider_provider_account_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_user_id_user_id_fk": { + "name": "apiKey_user_id_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "columns": ["board_id", "group_id", "permission"], + "name": "boardGroupPermission_board_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "columns": ["board_id", "user_id", "permission"], + "name": "boardUserPermission_board_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'fixed'" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'no-repeat'" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'cover'" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fa5252'" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fd7e14'" + }, + "opacity": { + "name": "opacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_group_id_group_id_fk": { + "name": "groupMember_group_id_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_user_id_user_id_fk": { + "name": "groupMember_user_id_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_group_id_user_id_pk": { + "columns": ["group_id", "user_id"], + "name": "groupMember_group_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_group_id_group_id_fk": { + "name": "groupPermission_group_id_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "group_name_unique": { + "name": "group_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "icon": { + "name": "icon", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_repository_id": { + "name": "icon_repository_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_icon_repository_id_iconRepository_id_fk": { + "name": "icon_icon_repository_id_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationGroupPermissions_integration_id_group_id_permission_pk": { + "columns": ["integration_id", "group_id", "permission"], + "name": "integrationGroupPermissions_integration_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "columns": ["item_id", "integration_id"], + "name": "integration_item_item_id_integration_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "columns": ["integration_id", "kind"], + "name": "integrationSecret_integration_id_kind_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "columns": ["integration_id", "user_id", "permission"], + "name": "integrationUserPermission_integration_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"], + "isUnique": true + } + }, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "media": { + "name": "media", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "blob", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "media_creator_id_user_id_fk": { + "name": "media_creator_id_user_id_fk", + "tableFrom": "media", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "onboarding": { + "name": "onboarding", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "step": { + "name": "step", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "previous_step": { + "name": "previous_step", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'generic'" + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "search_engine_short_unique": { + "name": "search_engine_short_unique", + "columns": ["short"], + "isUnique": true + } + }, + "foreignKeys": { + "search_engine_integration_id_integration_id_fk": { + "name": "search_engine_integration_id_integration_id_fk", + "tableFrom": "search_engine", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "setting_key": { + "name": "setting_key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": { + "serverSetting_settingKey_unique": { + "name": "serverSetting_settingKey_unique", + "columns": ["setting_key"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "session_token": { + "name": "session_token", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "home_board_id": { + "name": "home_board_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "default_search_engine_id": { + "name": "default_search_engine_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color_scheme": { + "name": "color_scheme", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "first_day_of_week": { + "name": "first_day_of_week", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "ping_icons_enabled": { + "name": "ping_icons_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_home_board_id_board_id_fk": { + "name": "user_home_board_id_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "user_default_search_engine_id_search_engine_id_fk": { + "name": "user_default_search_engine_id_search_engine_id_fk", + "tableFrom": "user", + "tableTo": "search_engine", + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": ["identifier", "token"], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/packages/db/migrations/sqlite/meta/0020_snapshot.json b/packages/db/migrations/sqlite/meta/0020_snapshot.json new file mode 100644 index 000000000..65af0e6a6 --- /dev/null +++ b/packages/db/migrations/sqlite/meta/0020_snapshot.json @@ -0,0 +1,1625 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "b3f4436c-11ae-4c7c-a242-ce4b2e134edd", + "prevId": "08cb7257-ba7e-4d4e-9fe7-85656fc115b0", + "tables": { + "account": { + "name": "account", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_account_id": { + "name": "provider_account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_provider_account_id_pk": { + "columns": ["provider", "provider_account_id"], + "name": "account_provider_provider_account_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "apiKey": { + "name": "apiKey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "apiKey_user_id_user_id_fk": { + "name": "apiKey_user_id_user_id_fk", + "tableFrom": "apiKey", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "app": { + "name": "app", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardGroupPermission": { + "name": "boardGroupPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardGroupPermission_board_id_board_id_fk": { + "name": "boardGroupPermission_board_id_board_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardGroupPermission_group_id_group_id_fk": { + "name": "boardGroupPermission_group_id_group_id_fk", + "tableFrom": "boardGroupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardGroupPermission_board_id_group_id_permission_pk": { + "columns": ["board_id", "group_id", "permission"], + "name": "boardGroupPermission_board_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "boardUserPermission": { + "name": "boardUserPermission", + "columns": { + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "boardUserPermission_board_id_board_id_fk": { + "name": "boardUserPermission_board_id_board_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "boardUserPermission_user_id_user_id_fk": { + "name": "boardUserPermission_user_id_user_id_fk", + "tableFrom": "boardUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "boardUserPermission_board_id_user_id_permission_pk": { + "columns": ["board_id", "user_id", "permission"], + "name": "boardUserPermission_board_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "board": { + "name": "board", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_public": { + "name": "is_public", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'fixed'" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'no-repeat'" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'cover'" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fa5252'" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'#fd7e14'" + }, + "opacity": { + "name": "opacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 10 + } + }, + "indexes": { + "board_name_unique": { + "name": "board_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "board_creator_id_user_id_fk": { + "name": "board_creator_id_user_id_fk", + "tableFrom": "board", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupMember": { + "name": "groupMember", + "columns": { + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupMember_group_id_group_id_fk": { + "name": "groupMember_group_id_group_id_fk", + "tableFrom": "groupMember", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "groupMember_user_id_user_id_fk": { + "name": "groupMember_user_id_user_id_fk", + "tableFrom": "groupMember", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "groupMember_group_id_user_id_pk": { + "columns": ["group_id", "user_id"], + "name": "groupMember_group_id_user_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groupPermission": { + "name": "groupPermission", + "columns": { + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groupPermission_group_id_group_id_fk": { + "name": "groupPermission_group_id_group_id_fk", + "tableFrom": "groupPermission", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "group": { + "name": "group", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "group_name_unique": { + "name": "group_name_unique", + "columns": ["name"], + "isUnique": true + } + }, + "foreignKeys": { + "group_owner_id_user_id_fk": { + "name": "group_owner_id_user_id_fk", + "tableFrom": "group", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "iconRepository": { + "name": "iconRepository", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "icon": { + "name": "icon", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon_repository_id": { + "name": "icon_repository_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "icon_icon_repository_id_iconRepository_id_fk": { + "name": "icon_icon_repository_id_iconRepository_id_fk", + "tableFrom": "icon", + "tableTo": "iconRepository", + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationGroupPermissions_integration_id_integration_id_fk": { + "name": "integrationGroupPermissions_integration_id_integration_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationGroupPermissions_group_id_group_id_fk": { + "name": "integrationGroupPermissions_group_id_group_id_fk", + "tableFrom": "integrationGroupPermissions", + "tableTo": "group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationGroupPermissions_integration_id_group_id_permission_pk": { + "columns": ["integration_id", "group_id", "permission"], + "name": "integrationGroupPermissions_integration_id_group_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration_item": { + "name": "integration_item", + "columns": { + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integration_item_item_id_item_id_fk": { + "name": "integration_item_item_id_item_id_fk", + "tableFrom": "integration_item", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integration_item_integration_id_integration_id_fk": { + "name": "integration_item_integration_id_integration_id_fk", + "tableFrom": "integration_item", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integration_item_item_id_integration_id_pk": { + "columns": ["item_id", "integration_id"], + "name": "integration_item_item_id_integration_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationSecret": { + "name": "integrationSecret", + "columns": { + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": ["kind"], + "isUnique": false + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "integrationSecret_integration_id_integration_id_fk": { + "name": "integrationSecret_integration_id_integration_id_fk", + "tableFrom": "integrationSecret", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationSecret_integration_id_kind_pk": { + "columns": ["integration_id", "kind"], + "name": "integrationSecret_integration_id_kind_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integrationUserPermission": { + "name": "integrationUserPermission", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "integrationUserPermission_integration_id_integration_id_fk": { + "name": "integrationUserPermission_integration_id_integration_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "integrationUserPermission_user_id_user_id_fk": { + "name": "integrationUserPermission_user_id_user_id_fk", + "tableFrom": "integrationUserPermission", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "integrationUserPermission_integration_id_user_id_permission_pk": { + "columns": ["integration_id", "user_id", "permission"], + "name": "integrationUserPermission_integration_id_user_id_permission_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "integration": { + "name": "integration", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invite": { + "name": "invite", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expiration_date": { + "name": "expiration_date", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invite_token_unique": { + "name": "invite_token_unique", + "columns": ["token"], + "isUnique": true + } + }, + "foreignKeys": { + "invite_creator_id_user_id_fk": { + "name": "invite_creator_id_user_id_fk", + "tableFrom": "invite", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "item": { + "name": "item", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": {}, + "foreignKeys": { + "item_section_id_section_id_fk": { + "name": "item_section_id_section_id_fk", + "tableFrom": "item", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "media": { + "name": "media", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "blob", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "media_creator_id_user_id_fk": { + "name": "media_creator_id_user_id_fk", + "tableFrom": "media", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "onboarding": { + "name": "onboarding", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "step": { + "name": "step", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "previous_step": { + "name": "previous_step", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "search_engine": { + "name": "search_engine", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "short": { + "name": "short", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'generic'" + }, + "integration_id": { + "name": "integration_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "search_engine_short_unique": { + "name": "search_engine_short_unique", + "columns": ["short"], + "isUnique": true + } + }, + "foreignKeys": { + "search_engine_integration_id_integration_id_fk": { + "name": "search_engine_integration_id_integration_id_fk", + "tableFrom": "search_engine", + "tableTo": "integration", + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "section": { + "name": "section", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_board_id_board_id_fk": { + "name": "section_board_id_board_id_fk", + "tableFrom": "section", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_parent_section_id_section_id_fk": { + "name": "section_parent_section_id_section_id_fk", + "tableFrom": "section", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "serverSetting": { + "name": "serverSetting", + "columns": { + "setting_key": { + "name": "setting_key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "indexes": { + "serverSetting_settingKey_unique": { + "name": "serverSetting_settingKey_unique", + "columns": ["setting_key"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "session_token": { + "name": "session_token", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'credentials'" + }, + "home_board_id": { + "name": "home_board_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "mobile_home_board_id": { + "name": "mobile_home_board_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "default_search_engine_id": { + "name": "default_search_engine_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color_scheme": { + "name": "color_scheme", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'dark'" + }, + "first_day_of_week": { + "name": "first_day_of_week", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "ping_icons_enabled": { + "name": "ping_icons_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_home_board_id_board_id_fk": { + "name": "user_home_board_id_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "user_mobile_home_board_id_board_id_fk": { + "name": "user_mobile_home_board_id_board_id_fk", + "tableFrom": "user", + "tableTo": "board", + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "user_default_search_engine_id_search_engine_id_fk": { + "name": "user_default_search_engine_id_search_engine_id_fk", + "tableFrom": "user", + "tableTo": "search_engine", + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": ["identifier", "token"], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/packages/db/migrations/sqlite/meta/_journal.json b/packages/db/migrations/sqlite/meta/_journal.json index 8367929b9..2f5e7b122 100644 --- a/packages/db/migrations/sqlite/meta/_journal.json +++ b/packages/db/migrations/sqlite/meta/_journal.json @@ -120,6 +120,34 @@ "when": 1732210918783, "tag": "0016_change_all_to_snake_case", "breakpoints": true + }, + { + "idx": 17, + "version": "6", + "when": 1733777395703, + "tag": "0017_small_rumiko_fujikawa", + "breakpoints": true + }, + { + "idx": 18, + "version": "6", + "when": 1735593831501, + "tag": "0018_cheerful_tattoo", + "breakpoints": true + }, + { + "idx": 19, + "version": "6", + "when": 1735651175378, + "tag": "0019_steady_darkhawk", + "breakpoints": true + }, + { + "idx": 20, + "version": "6", + "when": 1736510755691, + "tag": "0020_empty_hellfire_club", + "breakpoints": true } ] } diff --git a/packages/db/migrations/sqlite/migrate.ts b/packages/db/migrations/sqlite/migrate.ts index 420169677..e075a8d14 100644 --- a/packages/db/migrations/sqlite/migrate.ts +++ b/packages/db/migrations/sqlite/migrate.ts @@ -2,15 +2,16 @@ import Database from "better-sqlite3"; import { drizzle } from "drizzle-orm/better-sqlite3"; import { migrate } from "drizzle-orm/better-sqlite3/migrator"; -import { schema } from "../.."; +import { env } from "../../env"; +import * as sqliteSchema from "../../schema/sqlite"; import { seedDataAsync } from "../seed"; const migrationsFolder = process.argv[2] ?? "."; const migrateAsync = async () => { - const sqlite = new Database(process.env.DB_URL?.replace("file:", "")); + const sqlite = new Database(env.DB_URL.replace("file:", "")); - const db = drizzle(sqlite, { schema, casing: "snake_case" }); + const db = drizzle(sqlite, { schema: sqliteSchema, casing: "snake_case" }); migrate(db, { migrationsFolder }); diff --git a/packages/db/package.json b/packages/db/package.json index 41aa4c069..b32236469 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -7,10 +7,11 @@ "exports": { ".": "./index.ts", "./client": "./client.ts", - "./schema/sqlite": "./schema/sqlite.ts", + "./schema": "./schema/index.ts", "./test": "./test/index.ts", "./queries": "./queries/index.ts", - "./validationSchemas": "./validationSchemas.ts" + "./validationSchemas": "./validationSchemas.ts", + "./env": "./env.ts" }, "main": "./index.ts", "types": "./index.ts", @@ -21,16 +22,16 @@ "clean": "rm -rf .turbo node_modules", "format": "prettier --check . --ignore-path ../../.gitignore", "lint": "eslint", - "migration:mysql:drop": "drizzle-kit drop --config ./configs/mysql.config.ts", - "migration:mysql:generate": "drizzle-kit generate --config ./configs/mysql.config.ts", - "migration:mysql:run": "drizzle-kit migrate --config ./configs/mysql.config.ts && pnpm run seed", - "migration:sqlite:drop": "drizzle-kit drop --config ./configs/sqlite.config.ts", - "migration:sqlite:generate": "drizzle-kit generate --config ./configs/sqlite.config.ts", - "migration:sqlite:run": "drizzle-kit migrate --config ./configs/sqlite.config.ts && pnpm run seed", - "push:mysql": "drizzle-kit push --config ./configs/mysql.config.ts", - "push:sqlite": "drizzle-kit push --config ./configs/sqlite.config.ts", + "migration:mysql:drop": "pnpm with-env drizzle-kit drop --config ./configs/mysql.config.ts", + "migration:mysql:generate": "pnpm with-env drizzle-kit generate --config ./configs/mysql.config.ts", + "migration:mysql:run": "pnpm with-env drizzle-kit migrate --config ./configs/mysql.config.ts && pnpm run seed", + "migration:sqlite:drop": "pnpm with-env drizzle-kit drop --config ./configs/sqlite.config.ts", + "migration:sqlite:generate": "pnpm with-env drizzle-kit generate --config ./configs/sqlite.config.ts", + "migration:sqlite:run": "pnpm with-env drizzle-kit migrate --config ./configs/sqlite.config.ts && pnpm run seed", + "push:mysql": "pnpm with-env drizzle-kit push --config ./configs/mysql.config.ts", + "push:sqlite": "pnpm with-env drizzle-kit push --config ./configs/sqlite.config.ts", "seed": "pnpm with-env tsx ./migrations/run-seed.ts", - "studio": "drizzle-kit studio --config ./configs/sqlite.config.ts", + "studio": "pnpm with-env drizzle-kit studio --config ./configs/sqlite.config.ts", "typecheck": "tsc --noEmit", "with-env": "dotenv -e ../../.env --" }, @@ -42,23 +43,24 @@ "@homarr/log": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0", "@paralleldrive/cuid2": "^2.2.2", + "@t3-oss/env-nextjs": "^0.11.1", "@testcontainers/mysql": "^10.16.0", - "better-sqlite3": "^11.7.0", + "better-sqlite3": "^11.8.0", "dotenv": "^16.4.7", - "drizzle-kit": "^0.30.1", - "drizzle-orm": "^0.38.1", - "drizzle-zod": "^0.6.0", - "mysql2": "3.11.5" + "drizzle-kit": "^0.30.2", + "drizzle-orm": "^0.38.4", + "drizzle-zod": "^0.6.1", + "mysql2": "3.12.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/better-sqlite3": "7.6.12", - "dotenv-cli": "^7.4.4", - "eslint": "^9.16.0", + "dotenv-cli": "^8.0.0", + "eslint": "^9.18.0", "prettier": "^3.4.2", "tsx": "4.19.2", - "typescript": "^5.7.2" + "typescript": "^5.7.3" } } diff --git a/packages/db/queries/item.ts b/packages/db/queries/item.ts index 336270471..db048556f 100644 --- a/packages/db/queries/item.ts +++ b/packages/db/queries/item.ts @@ -3,7 +3,7 @@ import type { WidgetKind } from "@homarr/definitions"; import type { Database } from ".."; import { inArray } from ".."; import type { inferSupportedIntegrations } from "../../widgets/src"; -import { items } from "../schema/sqlite"; +import { items } from "../schema"; export const getItemsWithIntegrationsAsync = async ( db: Database, diff --git a/packages/db/queries/server-setting.ts b/packages/db/queries/server-setting.ts index a8039aa32..73f5156bc 100644 --- a/packages/db/queries/server-setting.ts +++ b/packages/db/queries/server-setting.ts @@ -5,7 +5,7 @@ import { defaultServerSettings, defaultServerSettingsKeys } from "@homarr/server import type { Database } from ".."; import { eq } from ".."; -import { serverSettings } from "../schema/sqlite"; +import { serverSettings } from "../schema"; export const getServerSettingsAsync = async (db: Database) => { const settings = await db.query.serverSettings.findMany(); diff --git a/packages/db/schema/index.ts b/packages/db/schema/index.ts new file mode 100644 index 000000000..20000f771 --- /dev/null +++ b/packages/db/schema/index.ts @@ -0,0 +1,45 @@ +import type { InferSelectModel } from "drizzle-orm"; + +import * as mysqlSchema from "./mysql"; +import * as sqliteSchema from "./sqlite"; + +type Schema = typeof sqliteSchema; + +const schema = process.env.DB_DRIVER === "mysql2" ? (mysqlSchema as unknown as Schema) : sqliteSchema; + +// Sadly we can't use export * from here as we have multiple possible exports +export const { + accounts, + apiKeys, + apps, + boardGroupPermissions, + boardUserPermissions, + boards, + groupMembers, + groupPermissions, + groups, + iconRepositories, + icons, + integrationGroupPermissions, + integrationItems, + integrationSecrets, + integrationUserPermissions, + integrations, + invites, + items, + medias, + onboarding, + searchEngines, + sections, + serverSettings, + sessions, + users, + verificationTokens, +} = schema; + +export type User = InferSelectModel; +export type Account = InferSelectModel; +export type Session = InferSelectModel; +export type VerificationToken = InferSelectModel; +export type Integration = InferSelectModel; +export type IntegrationSecret = InferSelectModel; diff --git a/packages/db/schema/mysql.ts b/packages/db/schema/mysql.ts index 822e06795..6b75bbf04 100644 --- a/packages/db/schema/mysql.ts +++ b/packages/db/schema/mysql.ts @@ -25,6 +25,7 @@ import type { IntegrationKind, IntegrationPermission, IntegrationSecretKind, + OnboardingStep, SearchEngineType, SectionKind, SupportedAuthProvider, @@ -61,6 +62,12 @@ export const users = mysqlTable("user", { homeBoardId: varchar({ length: 64 }).references((): AnyMySqlColumn => boards.id, { onDelete: "set null", }), + mobileHomeBoardId: varchar({ length: 64 }).references((): AnyMySqlColumn => boards.id, { + onDelete: "set null", + }), + defaultSearchEngineId: varchar({ length: 64 }).references(() => searchEngines.id, { + onDelete: "set null", + }), colorScheme: varchar({ length: 5 }).$type().default("dark").notNull(), firstDayOfWeek: tinyint().$type().default(1).notNull(), // Defaults to Monday pingIconsEnabled: boolean().default(false).notNull(), @@ -388,13 +395,19 @@ export const searchEngines = mysqlTable("search_engine", { id: varchar({ length: 64 }).notNull().primaryKey(), iconUrl: text().notNull(), name: varchar({ length: 64 }).notNull(), - short: varchar({ length: 8 }).notNull(), + short: varchar({ length: 8 }).unique().notNull(), description: text(), urlTemplate: text(), type: varchar({ length: 64 }).$type().notNull().default("generic"), integrationId: varchar({ length: 64 }).references(() => integrations.id, { onDelete: "cascade" }), }); +export const onboarding = mysqlTable("onboarding", { + id: varchar({ length: 64 }).notNull().primaryKey(), + step: varchar({ length: 64 }).$type().notNull(), + previousStep: varchar({ length: 64 }).$type(), +}); + export const accountRelations = relations(accounts, ({ one }) => ({ user: one(users, { fields: [accounts.userId], @@ -402,13 +415,17 @@ export const accountRelations = relations(accounts, ({ one }) => ({ }), })); -export const userRelations = relations(users, ({ many }) => ({ +export const userRelations = relations(users, ({ one, many }) => ({ accounts: many(accounts), boards: many(boards), boardPermissions: many(boardUserPermissions), groups: many(groupMembers), ownedGroups: many(groups), invites: many(invites), + defaultSearchEngine: one(searchEngines, { + fields: [users.defaultSearchEngineId], + references: [searchEngines.id], + }), })); export const mediaRelations = relations(medias, ({ one }) => ({ @@ -566,9 +583,10 @@ export const integrationItemRelations = relations(integrationItems, ({ one }) => }), })); -export const searchEngineRelations = relations(searchEngines, ({ one }) => ({ +export const searchEngineRelations = relations(searchEngines, ({ one, many }) => ({ integration: one(integrations, { fields: [searchEngines.integrationId], references: [integrations.id], }), + usersWithDefault: many(users), })); diff --git a/packages/db/schema/sqlite.ts b/packages/db/schema/sqlite.ts index fd4158f38..3640aefa4 100644 --- a/packages/db/schema/sqlite.ts +++ b/packages/db/schema/sqlite.ts @@ -1,6 +1,5 @@ import type { AdapterAccount } from "@auth/core/adapters"; import type { DayOfWeek } from "@mantine/dates"; -import type { InferSelectModel } from "drizzle-orm"; import { relations, sql } from "drizzle-orm"; import type { AnySQLiteColumn } from "drizzle-orm/sqlite-core"; import { blob, index, int, primaryKey, sqliteTable, text } from "drizzle-orm/sqlite-core"; @@ -16,6 +15,7 @@ import type { IntegrationKind, IntegrationPermission, IntegrationSecretKind, + OnboardingStep, SearchEngineType, SectionKind, SupportedAuthProvider, @@ -45,6 +45,12 @@ export const users = sqliteTable("user", { homeBoardId: text().references((): AnySQLiteColumn => boards.id, { onDelete: "set null", }), + mobileHomeBoardId: text().references((): AnySQLiteColumn => boards.id, { + onDelete: "set null", + }), + defaultSearchEngineId: text().references(() => searchEngines.id, { + onDelete: "set null", + }), colorScheme: text().$type().default("dark").notNull(), firstDayOfWeek: int().$type().default(1).notNull(), // Defaults to Monday pingIconsEnabled: int({ mode: "boolean" }).default(false).notNull(), @@ -375,13 +381,19 @@ export const searchEngines = sqliteTable("search_engine", { id: text().notNull().primaryKey(), iconUrl: text().notNull(), name: text().notNull(), - short: text().notNull(), + short: text().unique().notNull(), description: text(), urlTemplate: text(), type: text().$type().notNull().default("generic"), integrationId: text().references(() => integrations.id, { onDelete: "cascade" }), }); +export const onboarding = sqliteTable("onboarding", { + id: text().notNull().primaryKey(), + step: text().$type().notNull(), + previousStep: text().$type(), +}); + export const accountRelations = relations(accounts, ({ one }) => ({ user: one(users, { fields: [accounts.userId], @@ -389,7 +401,7 @@ export const accountRelations = relations(accounts, ({ one }) => ({ }), })); -export const userRelations = relations(users, ({ many }) => ({ +export const userRelations = relations(users, ({ one, many }) => ({ accounts: many(accounts), boards: many(boards), boardPermissions: many(boardUserPermissions), @@ -397,6 +409,10 @@ export const userRelations = relations(users, ({ many }) => ({ ownedGroups: many(groups), invites: many(invites), medias: many(medias), + defaultSearchEngine: one(searchEngines, { + fields: [users.defaultSearchEngineId], + references: [searchEngines.id], + }), })); export const mediaRelations = relations(medias, ({ one }) => ({ @@ -554,16 +570,10 @@ export const integrationItemRelations = relations(integrationItems, ({ one }) => }), })); -export const searchEngineRelations = relations(searchEngines, ({ one }) => ({ +export const searchEngineRelations = relations(searchEngines, ({ one, many }) => ({ integration: one(integrations, { fields: [searchEngines.integrationId], references: [integrations.id], }), + usersWithDefault: many(users), })); - -export type User = InferSelectModel; -export type Account = InferSelectModel; -export type Session = InferSelectModel; -export type VerificationToken = InferSelectModel; -export type Integration = InferSelectModel; -export type IntegrationSecret = InferSelectModel; diff --git a/packages/db/test/db-mock.ts b/packages/db/test/db-mock.ts index e2f249554..176a27534 100644 --- a/packages/db/test/db-mock.ts +++ b/packages/db/test/db-mock.ts @@ -2,11 +2,11 @@ import Database from "better-sqlite3"; import { drizzle } from "drizzle-orm/better-sqlite3"; import { migrate } from "drizzle-orm/better-sqlite3/migrator"; -import { schema } from ".."; +import * as sqliteSchema from "../schema/sqlite"; export const createDb = (debug?: boolean) => { const sqlite = new Database(":memory:"); - const db = drizzle(sqlite, { schema, logger: debug, casing: "snake_case" }); + const db = drizzle(sqlite, { schema: sqliteSchema, logger: debug, casing: "snake_case" }); migrate(db, { migrationsFolder: "./packages/db/migrations/sqlite", }); diff --git a/packages/db/transactions.ts b/packages/db/transactions.ts new file mode 100644 index 000000000..e7da4ae16 --- /dev/null +++ b/packages/db/transactions.ts @@ -0,0 +1,24 @@ +import type { HomarrDatabase, HomarrDatabaseMysql } from "./driver"; +import { env } from "./env"; +import * as mysqlSchema from "./schema/mysql"; + +type MysqlSchema = typeof mysqlSchema; + +interface HandleTransactionInput { + handleAsync: (db: HomarrDatabaseMysql, schema: MysqlSchema) => Promise; + handleSync: (db: HomarrDatabase) => void; +} + +/** + * The below method is mostly used to handle transactions in different database drivers. + * As better-sqlite3 transactions have to be synchronous, we have to implement them in a different way. + * But it can also generally be used when dealing with different database drivers. + */ +export const handleDiffrentDbDriverOperationsAsync = async (db: HomarrDatabase, input: HandleTransactionInput) => { + if (env.DB_DRIVER !== "mysql2") { + input.handleSync(db); + return; + } + + await input.handleAsync(db as unknown as HomarrDatabaseMysql, mysqlSchema); +}; diff --git a/packages/db/validationSchemas.ts b/packages/db/validationSchemas.ts index 584fdfa6f..da49819e3 100644 --- a/packages/db/validationSchemas.ts +++ b/packages/db/validationSchemas.ts @@ -1,6 +1,6 @@ import { createSelectSchema } from "drizzle-zod"; -import { apps, boards, groups, invites, searchEngines, serverSettings, users } from "./schema/sqlite"; +import { apps, boards, groups, invites, searchEngines, serverSettings, users } from "./schema"; export const selectAppSchema = createSelectSchema(apps); export const selectBoardSchema = createSelectSchema(boards); diff --git a/packages/definitions/package.json b/packages/definitions/package.json index 55d970fea..8fe5d1ee6 100644 --- a/packages/definitions/package.json +++ b/packages/definitions/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/definitions/src/docs/homarr-docs-sitemap.ts b/packages/definitions/src/docs/homarr-docs-sitemap.ts index 2210941e3..b733a9b67 100644 --- a/packages/definitions/src/docs/homarr-docs-sitemap.ts +++ b/packages/definitions/src/docs/homarr-docs-sitemap.ts @@ -8,6 +8,8 @@ export type HomarrDocumentationPath = | "/blog/2023/11/10/authentication" | "/blog/2023/12/22/updated-documentation" | "/blog/2024/09/23/version-1.0" + | "/blog/2024/12/17/open-beta-1.0" + | "/blog/2024/12/31/migrate-secret-enryption-key" | "/blog/archive" | "/blog/authors" | "/blog/authors/ajnart" @@ -33,6 +35,7 @@ export type HomarrDocumentationPath = | "/blog/tags/update" | "/blog/tags/version" | "/blog/translations" + | "/search" | "/docs/tags" | "/docs/tags/active-directory" | "/docs/tags/ad-guard" @@ -44,7 +47,6 @@ export type HomarrDocumentationPath = | "/docs/tags/apps" | "/docs/tags/banner" | "/docs/tags/blocking" - | "/docs/tags/board" | "/docs/tags/boards" | "/docs/tags/bookmark" | "/docs/tags/bookmarks" @@ -56,10 +58,12 @@ export type HomarrDocumentationPath = | "/docs/tags/connections" | "/docs/tags/customization" | "/docs/tags/data-sources" + | "/docs/tags/database" | "/docs/tags/developer" | "/docs/tags/development" | "/docs/tags/dns" | "/docs/tags/docker" + | "/docs/tags/donation" | "/docs/tags/edit-mode" | "/docs/tags/env" | "/docs/tags/environment-variables" @@ -71,6 +75,8 @@ export type HomarrDocumentationPath = | "/docs/tags/hardware" | "/docs/tags/health" | "/docs/tags/help" + | "/docs/tags/icon-picker" + | "/docs/tags/icon-repositories" | "/docs/tags/icons" | "/docs/tags/iframe" | "/docs/tags/images" @@ -84,20 +90,24 @@ export type HomarrDocumentationPath = | "/docs/tags/links" | "/docs/tags/lists" | "/docs/tags/management" + | "/docs/tags/media" + | "/docs/tags/minecraft" | "/docs/tags/monitoring" | "/docs/tags/news" | "/docs/tags/notebook" | "/docs/tags/notes" | "/docs/tags/oidc" + | "/docs/tags/open-collective" | "/docs/tags/open-media-vault" | "/docs/tags/overseerr" | "/docs/tags/permissions" + | "/docs/tags/pgid" | "/docs/tags/pi-hole" | "/docs/tags/ping" - | "/docs/tags/preferences" | "/docs/tags/programming" | "/docs/tags/proxmox" | "/docs/tags/proxy" + | "/docs/tags/puid" | "/docs/tags/roles" | "/docs/tags/rss" | "/docs/tags/search" @@ -112,39 +122,38 @@ export type HomarrDocumentationPath = | "/docs/tags/table" | "/docs/tags/technical-documentation" | "/docs/tags/text" - | "/docs/tags/theming" + | "/docs/tags/torrent" | "/docs/tags/traefik" | "/docs/tags/translations" | "/docs/tags/unraid" - | "/docs/tags/user" + | "/docs/tags/uploads" + | "/docs/tags/usenet" | "/docs/tags/users" | "/docs/tags/variables" | "/docs/tags/widgets" | "/docs/advanced/command-line" | "/docs/advanced/command-line/password-recovery" - | "/docs/advanced/configuration/environment-variables" - | "/docs/advanced/configuration/keyboard-shortcuts" - | "/docs/advanced/configuration/proxies-and-certificates" - | "/docs/advanced/customizations/board-customization" - | "/docs/advanced/customizations/dark-mode" - | "/docs/advanced/customizations/icons" - | "/docs/advanced/customizations/user-preferences" - | "/docs/advanced/sso" + | "/docs/advanced/development/getting-started" + | "/docs/advanced/environment-variables" + | "/docs/advanced/icons" + | "/docs/advanced/keyboard-shortcuts" + | "/docs/advanced/proxy" + | "/docs/advanced/running-as-different-user" + | "/docs/advanced/single-sign-on" | "/docs/category/advanced" - | "/docs/category/developer-guide" + | "/docs/category/community" + | "/docs/category/developer-guides" | "/docs/category/getting-started" | "/docs/category/installation" | "/docs/category/installation-1" | "/docs/category/integrations" | "/docs/category/management" - | "/docs/category/more" | "/docs/category/widgets" | "/docs/community/donate" | "/docs/community/faq" | "/docs/community/get-in-touch" | "/docs/community/license" | "/docs/community/translations" - | "/docs/development/getting-started" | "/docs/getting-started" | "/docs/getting-started/after-the-installation" | "/docs/getting-started/glossary" @@ -152,7 +161,6 @@ export type HomarrDocumentationPath = | "/docs/getting-started/installation/easy-panel" | "/docs/getting-started/installation/helm" | "/docs/getting-started/installation/home-assistant" - | "/docs/getting-started/installation/kubernetes" | "/docs/getting-started/installation/portainer" | "/docs/getting-started/installation/qnap" | "/docs/getting-started/installation/saltbox" @@ -172,26 +180,25 @@ export type HomarrDocumentationPath = | "/docs/management/apps" | "/docs/management/boards" | "/docs/management/integrations" + | "/docs/management/media" | "/docs/management/search-engines" | "/docs/management/settings" | "/docs/management/users" | "/docs/widgets/bookmarks" - | "/docs/widgets/calendar-widget" - | "/docs/widgets/clock-widget" - | "/docs/widgets/dashdot-widget" + | "/docs/widgets/calendar" + | "/docs/widgets/clock" | "/docs/widgets/dns-hole" - | "/docs/widgets/download-speed-widget" + | "/docs/widgets/downloads" | "/docs/widgets/health-monitoring" | "/docs/widgets/home-assistant" | "/docs/widgets/iframe" | "/docs/widgets/indexer-manager" | "/docs/widgets/media-requests" | "/docs/widgets/media-server" + | "/docs/widgets/minecraft-server-status" | "/docs/widgets/notebook" - | "/docs/widgets/rss-widget" - | "/docs/widgets/torrent-widget" - | "/docs/widgets/usenet-widget" + | "/docs/widgets/rss" | "/docs/widgets/video" - | "/docs/widgets/weather-widget" + | "/docs/widgets/weather" | "" | "/sitemap.xml"; diff --git a/packages/definitions/src/docs/index.ts b/packages/definitions/src/docs/index.ts index cc6c0f515..5d3c11f5c 100644 --- a/packages/definitions/src/docs/index.ts +++ b/packages/definitions/src/docs/index.ts @@ -1,6 +1,6 @@ import type { HomarrDocumentationPath } from "./homarr-docs-sitemap"; -const documentationBaseUrl = "https://deploy-preview-113--homarr-docs.netlify.app"; +const documentationBaseUrl = "https://homarr.dev"; // Please use the method so the path can be checked! export const createDocumentationLink = (path: HomarrDocumentationPath, hashTag?: `#${string}`) => diff --git a/packages/definitions/src/group.ts b/packages/definitions/src/group.ts index ebac0daa1..bf388c288 100644 --- a/packages/definitions/src/group.ts +++ b/packages/definitions/src/group.ts @@ -1 +1,2 @@ export const everyoneGroup = "everyone"; +export const credentialsAdminGroup = "credentials-admin"; diff --git a/packages/definitions/src/index.ts b/packages/definitions/src/index.ts index 12c878462..13cc03dd5 100644 --- a/packages/definitions/src/index.ts +++ b/packages/definitions/src/index.ts @@ -10,3 +10,4 @@ export * from "./group"; export * from "./docs"; export * from "./cookie"; export * from "./search-engine"; +export * from "./onboarding"; diff --git a/packages/definitions/src/integration.ts b/packages/definitions/src/integration.ts index 8c9645be9..17fa806d1 100644 --- a/packages/definitions/src/integration.ts +++ b/packages/definitions/src/integration.ts @@ -5,6 +5,8 @@ export const integrationSecretKindObject = { apiKey: { isPublic: false }, username: { isPublic: true }, password: { isPublic: false }, + tokenId: { isPublic: true }, + realm: { isPublic: true }, } satisfies Record; export const integrationSecretKinds = objectKeys(integrationSecretKindObject); @@ -14,142 +16,134 @@ interface integrationDefinition { iconUrl: string; secretKinds: AtLeastOneOf; // at least one secret kind set is required category: AtLeastOneOf; - supportsSearch: boolean; } export const integrationDefs = { sabNzbd: { name: "SABnzbd", secretKinds: [["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/sabnzbd.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/sabnzbd.png", category: ["downloadClient", "usenet"], - supportsSearch: false, }, nzbGet: { name: "NZBGet", secretKinds: [["username", "password"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/nzbget.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/nzbget.png", category: ["downloadClient", "usenet"], - supportsSearch: false, }, deluge: { name: "Deluge", secretKinds: [["password"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/deluge.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/deluge.png", category: ["downloadClient", "torrent"], - supportsSearch: false, }, transmission: { name: "Transmission", secretKinds: [["username", "password"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/transmission.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/transmission.png", category: ["downloadClient", "torrent"], - supportsSearch: false, }, qBittorrent: { name: "qBittorrent", secretKinds: [["username", "password"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/qbittorrent.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/qbittorrent.png", category: ["downloadClient", "torrent"], - supportsSearch: false, }, sonarr: { name: "Sonarr", secretKinds: [["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/sonarr.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/sonarr.png", category: ["calendar"], - supportsSearch: false, }, radarr: { name: "Radarr", secretKinds: [["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/radarr.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/radarr.png", category: ["calendar"], - supportsSearch: false, }, lidarr: { name: "Lidarr", secretKinds: [["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/lidarr.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/lidarr.png", category: ["calendar"], - supportsSearch: false, }, readarr: { name: "Readarr", secretKinds: [["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/readarr.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/readarr.png", category: ["calendar"], - supportsSearch: false, }, prowlarr: { name: "Prowlarr", secretKinds: [["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/prowlarr.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/prowlarr.png", category: ["indexerManager"], - supportsSearch: false, }, jellyfin: { name: "Jellyfin", secretKinds: [["username", "password"], ["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/jellyfin.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/jellyfin.png", category: ["mediaService"], - supportsSearch: false, }, plex: { name: "Plex", secretKinds: [["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/plex.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/plex.png", category: ["mediaService"], - supportsSearch: false, }, jellyseerr: { name: "Jellyseerr", secretKinds: [["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/jellyseerr.png", - category: ["mediaSearch", "mediaRequest"], - supportsSearch: true, + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/jellyseerr.png", + category: ["mediaSearch", "mediaRequest", "search"], }, overseerr: { name: "Overseerr", secretKinds: [["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/overseerr.png", - category: ["mediaSearch", "mediaRequest"], - supportsSearch: true, + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/overseerr.png", + category: ["mediaSearch", "mediaRequest", "search"], }, piHole: { name: "Pi-hole", secretKinds: [["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/pi-hole.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/pi-hole.png", category: ["dnsHole"], - supportsSearch: false, }, adGuardHome: { name: "AdGuard Home", secretKinds: [["username", "password"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/adguard-home.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/adguard-home.png", category: ["dnsHole"], - supportsSearch: false, }, homeAssistant: { name: "Home Assistant", secretKinds: [["apiKey"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/home-assistant.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/home-assistant.png", category: ["smartHomeServer"], - supportsSearch: false, }, openmediavault: { name: "OpenMediaVault", secretKinds: [["username", "password"]], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/openmediavault.png", + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/openmediavault.png", category: ["healthMonitoring"], - supportsSearch: false, }, dashDot: { name: "Dash.", secretKinds: [[]], category: ["healthMonitoring"], - iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/dashdot.png", - supportsSearch: false, + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/dashdot.png", + }, + tdarr: { + name: "Tdarr", + secretKinds: [[]], + category: ["mediaTranscoding"], + iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/tdarr.png", + }, + proxmox: { + name: "Proxmox", + secretKinds: [["username", "tokenId", "apiKey", "realm"]], + category: ["healthMonitoring"], + iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/proxmox.png", }, } as const satisfies Record; @@ -188,22 +182,6 @@ export type IntegrationKindByCategory = { U : never; -/** - * Checks if search is supported by the integration - * Uses a typescript guard with is to allow only integrations with search support within if statement - * @param integration integration with kind - * @returns true if the integration supports search - */ -export const isIntegrationWithSearchSupport = (integration: { - kind: IntegrationKind; -}): integration is { kind: IntegrationWithSearchSupport } => { - return integrationDefs[integration.kind].supportsSearch; -}; - -type IntegrationWithSearchSupport = { - [Key in keyof typeof integrationDefs]: true extends (typeof integrationDefs)[Key]["supportsSearch"] ? Key : never; -}[keyof typeof integrationDefs]; - export type IntegrationSecretKind = keyof typeof integrationSecretKindObject; export type IntegrationKind = keyof typeof integrationDefs; export type IntegrationCategory = @@ -217,4 +195,6 @@ export type IntegrationCategory = | "torrent" | "smartHomeServer" | "indexerManager" - | "healthMonitoring"; + | "healthMonitoring" + | "search" + | "mediaTranscoding"; diff --git a/packages/definitions/src/onboarding.ts b/packages/definitions/src/onboarding.ts new file mode 100644 index 000000000..d9a6ea03e --- /dev/null +++ b/packages/definitions/src/onboarding.ts @@ -0,0 +1,2 @@ +export const onboardingSteps = ["start", "import", "user", "group", "settings", "finish"] as const; +export type OnboardingStep = (typeof onboardingSteps)[number]; diff --git a/packages/definitions/src/widget.ts b/packages/definitions/src/widget.ts index 0f68c6577..a829b9ae8 100644 --- a/packages/definitions/src/widget.ts +++ b/packages/definitions/src/widget.ts @@ -14,6 +14,8 @@ export const widgetKinds = [ "downloads", "mediaRequests-requestList", "mediaRequests-requestStats", + "mediaTranscoding", + "minecraftServerStatus", "rssFeed", "bookmarks", "indexerManager", diff --git a/packages/form/package.json b/packages/form/package.json index b6894adfe..f765c86de 100644 --- a/packages/form/package.json +++ b/packages/form/package.json @@ -5,7 +5,8 @@ "license": "MIT", "type": "module", "exports": { - ".": "./index.ts" + ".": "./index.ts", + "./types": "./src/types.ts" }, "typesVersions": { "*": { @@ -22,15 +23,16 @@ }, "prettier": "@homarr/prettier-config", "dependencies": { + "@homarr/common": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/form": "^7.15.1" + "@mantine/form": "^7.16.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/form/src/types.ts b/packages/form/src/types.ts new file mode 100644 index 000000000..4c6c1363a --- /dev/null +++ b/packages/form/src/types.ts @@ -0,0 +1,21 @@ +import type { ChangeEvent, FocusEvent } from "react"; + +export interface InputPropsFor + extends BasePropsFor { + value?: T; + defaultValue?: T; +} + +interface BasePropsFor { + onChange: (value: TOnChangeArg) => void; + error?: string; + onBlur?: (event: FocusEvent) => void; + onFocus?: (event: FocusEvent) => void; +} + +export interface CheckboxProps< + TOnChangeArg = ChangeEvent, + TComponent extends HTMLElement = HTMLInputElement, +> extends BasePropsFor { + checked?: boolean; +} diff --git a/packages/icons/index.ts b/packages/icons/index.ts index eb96ce46b..59a0b28ba 100644 --- a/packages/icons/index.ts +++ b/packages/icons/index.ts @@ -1,2 +1,3 @@ export * from "./src/icons-fetcher"; export * from "./src/types"; +export * from "./src/auto-icon-searcher"; diff --git a/packages/icons/package.json b/packages/icons/package.json index c82b0bcda..d213eb733 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -5,7 +5,8 @@ "license": "MIT", "type": "module", "exports": { - ".": "./index.ts" + ".": "./index.ts", + "./local": "./src/local.ts" }, "typesVersions": { "*": { @@ -30,7 +31,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/icons/src/auto-icon-searcher.ts b/packages/icons/src/auto-icon-searcher.ts new file mode 100644 index 000000000..06f3d9b76 --- /dev/null +++ b/packages/icons/src/auto-icon-searcher.ts @@ -0,0 +1,9 @@ +import type { Database } from "@homarr/db"; +import { like } from "@homarr/db"; +import { icons } from "@homarr/db/schema"; + +export const getIconForName = (db: Database, name: string) => { + return db.query.icons.findFirst({ + where: like(icons.name, `%${name}%`), + }); +}; diff --git a/packages/icons/src/icons-fetcher.ts b/packages/icons/src/icons-fetcher.ts index d1be6a75a..b9ab3c450 100644 --- a/packages/icons/src/icons-fetcher.ts +++ b/packages/icons/src/icons-fetcher.ts @@ -5,12 +5,12 @@ import type { RepositoryIconGroup } from "./types"; const repositories = [ new GitHubIconRepository( - "Walkxcode", - "walkxcode/dashboard-icons", + "Dashboard Icons", + "homarr-labs/dashboard-icons", undefined, - new URL("https://github.com/walkxcode/dashboard-icons"), - new URL("https://api.github.com/repos/walkxcode/dashboard-icons/git/trees/main?recursive=true"), - "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/{0}", + new URL("https://github.com/homarr-labs/dashboard-icons"), + new URL("https://api.github.com/repos/homarr-labs/dashboard-icons/git/trees/main?recursive=true"), + "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/{0}", ), new GitHubIconRepository( "selfh.st", diff --git a/packages/icons/src/local.ts b/packages/icons/src/local.ts new file mode 100644 index 000000000..a7ca63c45 --- /dev/null +++ b/packages/icons/src/local.ts @@ -0,0 +1 @@ +export { createLocalImageUrl, mapMediaToIcon, LOCAL_ICON_REPOSITORY_SLUG } from "./repositories/local.icon-repository"; diff --git a/packages/icons/src/repositories/local.icon-repository.ts b/packages/icons/src/repositories/local.icon-repository.ts index 7fc7c74d9..c0d9a5b27 100644 --- a/packages/icons/src/repositories/local.icon-repository.ts +++ b/packages/icons/src/repositories/local.icon-repository.ts @@ -1,26 +1,36 @@ import { createHash } from "crypto"; +import type { InferSelectModel } from "@homarr/db"; import { db } from "@homarr/db"; +import type { medias } from "@homarr/db/schema"; -import type { RepositoryIconGroup } from "../types"; +import type { RepositoryIcon, RepositoryIconGroup } from "../types"; import { IconRepository } from "./icon-repository"; +export const LOCAL_ICON_REPOSITORY_SLUG = "local"; + export class LocalIconRepository extends IconRepository { constructor() { - super("Local", "local", undefined, undefined, undefined, undefined); + super("Local", LOCAL_ICON_REPOSITORY_SLUG, undefined, undefined, undefined, undefined); } protected async getAllIconsInternalAsync(): Promise { const medias = await db.query.medias.findMany(); return { success: true, - icons: medias.map((media) => ({ - local: true, - fileNameWithExtension: media.name, - imageUrl: `/api/user-medias/${media.id}`, - checksum: createHash("md5").update(media.content).digest("hex"), - sizeInBytes: media.size, - })), - slug: "local", + icons: medias.map(mapMediaToIcon), + slug: LOCAL_ICON_REPOSITORY_SLUG, }; } } + +export const createLocalImageUrl = (id: string) => `/api/user-medias/${id}`; + +export const mapMediaToIcon = ( + media: Pick, "name" | "id" | "content" | "size">, +): RepositoryIcon => ({ + local: true, + fileNameWithExtension: media.name, + imageUrl: createLocalImageUrl(media.id), + checksum: createHash("md5").update(media.content).digest("hex"), + sizeInBytes: media.size, +}); diff --git a/packages/integrations/package.json b/packages/integrations/package.json index b5e125176..ea88e109f 100644 --- a/packages/integrations/package.json +++ b/packages/integrations/package.json @@ -24,9 +24,10 @@ }, "prettier": "@homarr/prettier-config", "dependencies": { - "@ctrl/deluge": "^7.0.0", - "@ctrl/qbittorrent": "^9.1.0", - "@ctrl/transmission": "^7.1.0", + "@ctrl/deluge": "^7.1.0", + "@ctrl/qbittorrent": "^9.2.0", + "@ctrl/transmission": "^7.2.0", + "@homarr/certificates": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", @@ -35,6 +36,8 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", "@jellyfin/sdk": "^0.11.0", + "proxmox-api": "1.1.1", + "undici": "7.2.3", "xml2js": "^0.6.2" }, "devDependencies": { @@ -42,7 +45,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/xml2js": "^0.4.14", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/integrations/src/adguard-home/adguard-home-integration.ts b/packages/integrations/src/adguard-home/adguard-home-integration.ts index d7aca6add..2ba8880ef 100644 --- a/packages/integrations/src/adguard-home/adguard-home-integration.ts +++ b/packages/integrations/src/adguard-home/adguard-home-integration.ts @@ -1,3 +1,5 @@ +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; + import { Integration } from "../base/integration"; import { IntegrationTestConnectionError } from "../base/test-connection-error"; import type { DnsHoleSummaryIntegration } from "../interfaces/dns-hole-summary/dns-hole-summary-integration"; @@ -6,7 +8,7 @@ import { filteringStatusSchema, statsResponseSchema, statusResponseSchema } from export class AdGuardHomeIntegration extends Integration implements DnsHoleSummaryIntegration { public async getSummaryAsync(): Promise { - const statsResponse = await fetch(this.url("/control/stats"), { + const statsResponse = await fetchWithTrustedCertificatesAsync(this.url("/control/stats"), { headers: { Authorization: `Basic ${this.getAuthorizationHeaderValue()}`, }, @@ -18,7 +20,7 @@ export class AdGuardHomeIntegration extends Integration implements DnsHoleSummar ); } - const statusResponse = await fetch(this.url("/control/status"), { + const statusResponse = await fetchWithTrustedCertificatesAsync(this.url("/control/status"), { headers: { Authorization: `Basic ${this.getAuthorizationHeaderValue()}`, }, @@ -30,7 +32,7 @@ export class AdGuardHomeIntegration extends Integration implements DnsHoleSummar ); } - const filteringStatusResponse = await fetch(this.url("/control/filtering/status"), { + const filteringStatusResponse = await fetchWithTrustedCertificatesAsync(this.url("/control/filtering/status"), { headers: { Authorization: `Basic ${this.getAuthorizationHeaderValue()}`, }, @@ -86,7 +88,7 @@ export class AdGuardHomeIntegration extends Integration implements DnsHoleSummar public async testConnectionAsync(): Promise { await super.handleTestConnectionResponseAsync({ queryFunctionAsync: async () => { - return await fetch(this.url("/control/status"), { + return await fetchWithTrustedCertificatesAsync(this.url("/control/status"), { headers: { Authorization: `Basic ${this.getAuthorizationHeaderValue()}`, }, @@ -94,7 +96,7 @@ export class AdGuardHomeIntegration extends Integration implements DnsHoleSummar }, handleResponseAsync: async (response) => { try { - const result = (await response.json()) as unknown; + const result = await response.json(); if (typeof result === "object" && result !== null) return; } catch { throw new IntegrationTestConnectionError("invalidJson"); @@ -106,7 +108,7 @@ export class AdGuardHomeIntegration extends Integration implements DnsHoleSummar } public async enableAsync(): Promise { - const response = await fetch(this.url("/control/protection"), { + const response = await fetchWithTrustedCertificatesAsync(this.url("/control/protection"), { method: "POST", headers: { "Content-Type": "application/json", @@ -124,7 +126,7 @@ export class AdGuardHomeIntegration extends Integration implements DnsHoleSummar } public async disableAsync(duration = 0): Promise { - const response = await fetch(this.url("/control/protection"), { + const response = await fetchWithTrustedCertificatesAsync(this.url("/control/protection"), { method: "POST", headers: { "Content-Type": "application/json", diff --git a/packages/integrations/src/base/creator.ts b/packages/integrations/src/base/creator.ts index 54643e4db..ecf184ba8 100644 --- a/packages/integrations/src/base/creator.ts +++ b/packages/integrations/src/base/creator.ts @@ -1,6 +1,6 @@ import { decryptSecret } from "@homarr/common/server"; import type { Modify } from "@homarr/common/types"; -import type { Integration as DbIntegration } from "@homarr/db/schema/sqlite"; +import type { Integration as DbIntegration } from "@homarr/db/schema"; import type { IntegrationKind, IntegrationSecretKind } from "@homarr/definitions"; import { AdGuardHomeIntegration } from "../adguard-home/adguard-home-integration"; @@ -17,11 +17,13 @@ import { LidarrIntegration } from "../media-organizer/lidarr/lidarr-integration" import { RadarrIntegration } from "../media-organizer/radarr/radarr-integration"; import { ReadarrIntegration } from "../media-organizer/readarr/readarr-integration"; import { SonarrIntegration } from "../media-organizer/sonarr/sonarr-integration"; +import { TdarrIntegration } from "../media-transcoding/tdarr-integration"; import { OpenMediaVaultIntegration } from "../openmediavault/openmediavault-integration"; import { OverseerrIntegration } from "../overseerr/overseerr-integration"; import { PiHoleIntegration } from "../pi-hole/pi-hole-integration"; import { PlexIntegration } from "../plex/plex-integration"; import { ProwlarrIntegration } from "../prowlarr/prowlarr-integration"; +import { ProxmoxIntegration } from "../proxmox/proxmox-integration"; import type { Integration, IntegrationInput } from "./integration"; export const integrationCreator = ( @@ -70,4 +72,6 @@ export const integrationCreators = { lidarr: LidarrIntegration, readarr: ReadarrIntegration, dashDot: DashDotIntegration, + tdarr: TdarrIntegration, + proxmox: ProxmoxIntegration, } satisfies Record Integration>; diff --git a/packages/integrations/src/base/integration.ts b/packages/integrations/src/base/integration.ts index c9c953443..dbfee6ccc 100644 --- a/packages/integrations/src/base/integration.ts +++ b/packages/integrations/src/base/integration.ts @@ -1,3 +1,5 @@ +import type { Response } from "undici"; + import { extractErrorMessage, removeTrailingSlash } from "@homarr/common"; import type { IntegrationSecretKind } from "@homarr/definitions"; import { logger } from "@homarr/log"; @@ -29,6 +31,10 @@ export abstract class Integration { return secret.value; } + protected hasSecretValue(kind: IntegrationSecretKind) { + return this.integration.decryptedSecrets.some((secret) => secret.kind === kind); + } + protected url(path: `/${string}`, queryParams?: Record) { const baseUrl = removeTrailingSlash(this.integration.url); const url = new URL(`${baseUrl}${path}`); diff --git a/packages/integrations/src/base/searchable-integration.ts b/packages/integrations/src/base/searchable-integration.ts index 918c3b07f..2b92fe4e7 100644 --- a/packages/integrations/src/base/searchable-integration.ts +++ b/packages/integrations/src/base/searchable-integration.ts @@ -1,3 +1,3 @@ -export interface ISearchableIntegration { - searchAsync(query: string): Promise<{ image?: string; name: string; link: string }[]>; +export interface ISearchableIntegration { + searchAsync(query: string): Promise; } diff --git a/packages/integrations/src/dashdot/dashdot-integration.ts b/packages/integrations/src/dashdot/dashdot-integration.ts index 271e17409..315c46177 100644 --- a/packages/integrations/src/dashdot/dashdot-integration.ts +++ b/packages/integrations/src/dashdot/dashdot-integration.ts @@ -4,6 +4,7 @@ import "@homarr/redis"; import dayjs from "dayjs"; +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; import { z } from "@homarr/validation"; import { createChannelEventHistory } from "../../../redis/src/lib/channel"; @@ -12,7 +13,7 @@ import type { HealthMonitoring } from "../types"; export class DashDotIntegration extends Integration { public async testConnectionAsync(): Promise { - const response = await fetch(this.url("/info")); + const response = await fetchWithTrustedCertificatesAsync(this.url("/info")); await response.json(); } @@ -52,7 +53,7 @@ export class DashDotIntegration extends Integration { } private async getInfoAsync() { - const infoResponse = await fetch(this.url("/info")); + const infoResponse = await fetchWithTrustedCertificatesAsync(this.url("/info")); const serverInfo = await internalServerInfoApi.parseAsync(await infoResponse.json()); return { maxAvailableMemoryBytes: serverInfo.ram.size, @@ -66,7 +67,7 @@ export class DashDotIntegration extends Integration { private async getCurrentCpuLoadAsync() { const channel = this.getChannel(); - const cpu = await fetch(this.url("/load/cpu")); + const cpu = await fetchWithTrustedCertificatesAsync(this.url("/load/cpu")); const data = await cpuLoadPerCoreApiList.parseAsync(await cpu.json()); await channel.pushAsync(data); return { @@ -88,12 +89,12 @@ export class DashDotIntegration extends Integration { } private async getCurrentStorageLoadAsync() { - const storageLoad = await fetch(this.url("/load/storage")); + const storageLoad = await fetchWithTrustedCertificatesAsync(this.url("/load/storage")); return (await storageLoad.json()) as number[]; } private async getCurrentMemoryLoadAsync() { - const memoryLoad = await fetch(this.url("/load/ram")); + const memoryLoad = await fetchWithTrustedCertificatesAsync(this.url("/load/ram")); const data = await memoryLoadApi.parseAsync(await memoryLoad.json()); return { loadInBytes: data.load, diff --git a/packages/integrations/src/download-client/deluge/deluge-integration.ts b/packages/integrations/src/download-client/deluge/deluge-integration.ts index 29067f2c0..80c04b180 100644 --- a/packages/integrations/src/download-client/deluge/deluge-integration.ts +++ b/packages/integrations/src/download-client/deluge/deluge-integration.ts @@ -1,6 +1,8 @@ import { Deluge } from "@ctrl/deluge"; import dayjs from "dayjs"; +import { createCertificateAgentAsync } from "@homarr/certificates/server"; + import type { DownloadClientJobsAndStatus } from "../../interfaces/downloads/download-client-data"; import { DownloadClientIntegration } from "../../interfaces/downloads/download-client-integration"; import type { DownloadClientItem } from "../../interfaces/downloads/download-client-items"; @@ -8,13 +10,13 @@ import type { DownloadClientStatus } from "../../interfaces/downloads/download-c export class DelugeIntegration extends DownloadClientIntegration { public async testConnectionAsync(): Promise { - const client = this.getClient(); + const client = await this.getClientAsync(); await client.login(); } public async getClientJobsAndStatusAsync(): Promise { const type = "torrent"; - const client = this.getClient(); + const client = await this.getClientAsync(); const { stats: { download_rate, upload_rate }, torrents: rawTorrents, @@ -57,7 +59,7 @@ export class DelugeIntegration extends DownloadClientIntegration { } public async pauseQueueAsync() { - const client = this.getClient(); + const client = await this.getClientAsync(); const store = (await client.listTorrents()).result.torrents; await Promise.all( Object.entries(store).map(async ([id]) => { @@ -67,11 +69,12 @@ export class DelugeIntegration extends DownloadClientIntegration { } public async pauseItemAsync({ id }: DownloadClientItem): Promise { - await this.getClient().pauseTorrent(id); + const client = await this.getClientAsync(); + await client.pauseTorrent(id); } public async resumeQueueAsync() { - const client = this.getClient(); + const client = await this.getClientAsync(); const store = (await client.listTorrents()).result.torrents; await Promise.all( Object.entries(store).map(async ([id]) => { @@ -81,17 +84,20 @@ export class DelugeIntegration extends DownloadClientIntegration { } public async resumeItemAsync({ id }: DownloadClientItem): Promise { - await this.getClient().resumeTorrent(id); + const client = await this.getClientAsync(); + await client.resumeTorrent(id); } public async deleteItemAsync({ id }: DownloadClientItem, fromDisk: boolean): Promise { - await this.getClient().removeTorrent(id, fromDisk); + const client = await this.getClientAsync(); + await client.removeTorrent(id, fromDisk); } - private getClient() { + private async getClientAsync() { return new Deluge({ baseUrl: this.url("/").toString(), password: this.getSecretValue("password"), + dispatcher: await createCertificateAgentAsync(), }); } diff --git a/packages/integrations/src/download-client/nzbget/nzbget-integration.ts b/packages/integrations/src/download-client/nzbget/nzbget-integration.ts index b17af0a87..ca2215624 100644 --- a/packages/integrations/src/download-client/nzbget/nzbget-integration.ts +++ b/packages/integrations/src/download-client/nzbget/nzbget-integration.ts @@ -1,5 +1,7 @@ import dayjs from "dayjs"; +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; + import type { DownloadClientJobsAndStatus } from "../../interfaces/downloads/download-client-data"; import { DownloadClientIntegration } from "../../interfaces/downloads/download-client-integration"; import type { DownloadClientItem } from "../../interfaces/downloads/download-client-items"; @@ -96,7 +98,7 @@ export class NzbGetIntegration extends DownloadClientIntegration { const password = this.getSecretValue("password"); const url = this.url(`/${username}:${password}/jsonrpc`); const body = JSON.stringify({ method, params }); - return await fetch(url, { method: "POST", body }) + return await fetchWithTrustedCertificatesAsync(url, { method: "POST", body }) .then(async (response) => { if (!response.ok) { throw new Error(response.statusText); diff --git a/packages/integrations/src/download-client/qbittorrent/qbittorrent-integration.ts b/packages/integrations/src/download-client/qbittorrent/qbittorrent-integration.ts index 2932e47c4..e15acab5e 100644 --- a/packages/integrations/src/download-client/qbittorrent/qbittorrent-integration.ts +++ b/packages/integrations/src/download-client/qbittorrent/qbittorrent-integration.ts @@ -1,6 +1,8 @@ import { QBittorrent } from "@ctrl/qbittorrent"; import dayjs from "dayjs"; +import { createCertificateAgentAsync } from "@homarr/certificates/server"; + import type { DownloadClientJobsAndStatus } from "../../interfaces/downloads/download-client-data"; import { DownloadClientIntegration } from "../../interfaces/downloads/download-client-integration"; import type { DownloadClientItem } from "../../interfaces/downloads/download-client-items"; @@ -8,13 +10,13 @@ import type { DownloadClientStatus } from "../../interfaces/downloads/download-c export class QBitTorrentIntegration extends DownloadClientIntegration { public async testConnectionAsync(): Promise { - const client = this.getClient(); + const client = await this.getClientAsync(); await client.login(); } public async getClientJobsAndStatusAsync(): Promise { const type = "torrent"; - const client = this.getClient(); + const client = await this.getClientAsync(); const torrents = await client.listTorrents(); const rates = torrents.reduce( ({ down, up }, { dlspeed, upspeed }) => ({ down: down + dlspeed, up: up + upspeed }), @@ -50,30 +52,36 @@ export class QBitTorrentIntegration extends DownloadClientIntegration { } public async pauseQueueAsync() { - await this.getClient().pauseTorrent("all"); + const client = await this.getClientAsync(); + await client.pauseTorrent("all"); } public async pauseItemAsync({ id }: DownloadClientItem): Promise { - await this.getClient().pauseTorrent(id); + const client = await this.getClientAsync(); + await client.pauseTorrent(id); } public async resumeQueueAsync() { - await this.getClient().resumeTorrent("all"); + const client = await this.getClientAsync(); + await client.resumeTorrent("all"); } public async resumeItemAsync({ id }: DownloadClientItem): Promise { - await this.getClient().resumeTorrent(id); + const client = await this.getClientAsync(); + await client.resumeTorrent(id); } public async deleteItemAsync({ id }: DownloadClientItem, fromDisk: boolean): Promise { - await this.getClient().removeTorrent(id, fromDisk); + const client = await this.getClientAsync(); + await client.removeTorrent(id, fromDisk); } - private getClient() { + private async getClientAsync() { return new QBittorrent({ baseUrl: this.url("/").toString(), username: this.getSecretValue("username"), password: this.getSecretValue("password"), + dispatcher: await createCertificateAgentAsync(), }); } diff --git a/packages/integrations/src/download-client/sabnzbd/sabnzbd-integration.ts b/packages/integrations/src/download-client/sabnzbd/sabnzbd-integration.ts index 644420644..6da299198 100644 --- a/packages/integrations/src/download-client/sabnzbd/sabnzbd-integration.ts +++ b/packages/integrations/src/download-client/sabnzbd/sabnzbd-integration.ts @@ -1,6 +1,8 @@ import dayjs from "dayjs"; import duration from "dayjs/plugin/duration"; +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; + import type { DownloadClientJobsAndStatus } from "../../interfaces/downloads/download-client-data"; import { DownloadClientIntegration } from "../../interfaces/downloads/download-client-integration"; import type { DownloadClientItem } from "../../interfaces/downloads/download-client-items"; @@ -106,12 +108,12 @@ export class SabnzbdIntegration extends DownloadClientIntegration { apikey: this.getSecretValue("apiKey"), }); - return await fetch(url) + return await fetchWithTrustedCertificatesAsync(url) .then((response) => { if (!response.ok) { throw new Error(response.statusText); } - return response.json() as Promise; + return response.json(); }) .catch((error) => { if (error instanceof Error) { diff --git a/packages/integrations/src/download-client/transmission/transmission-integration.ts b/packages/integrations/src/download-client/transmission/transmission-integration.ts index 919da6815..eefc01cde 100644 --- a/packages/integrations/src/download-client/transmission/transmission-integration.ts +++ b/packages/integrations/src/download-client/transmission/transmission-integration.ts @@ -1,6 +1,8 @@ import { Transmission } from "@ctrl/transmission"; import dayjs from "dayjs"; +import { createCertificateAgentAsync } from "@homarr/certificates/server"; + import type { DownloadClientJobsAndStatus } from "../../interfaces/downloads/download-client-data"; import { DownloadClientIntegration } from "../../interfaces/downloads/download-client-integration"; import type { DownloadClientItem } from "../../interfaces/downloads/download-client-items"; @@ -8,12 +10,13 @@ import type { DownloadClientStatus } from "../../interfaces/downloads/download-c export class TransmissionIntegration extends DownloadClientIntegration { public async testConnectionAsync(): Promise { - await this.getClient().getSession(); + const client = await this.getClientAsync(); + await client.getSession(); } public async getClientJobsAndStatusAsync(): Promise { const type = "torrent"; - const client = this.getClient(); + const client = await this.getClientAsync(); const { torrents } = (await client.listTorrents()).arguments; const rates = torrents.reduce( ({ down, up }, { rateDownload, rateUpload }) => ({ down: down + rateDownload, up: up + rateUpload }), @@ -47,34 +50,38 @@ export class TransmissionIntegration extends DownloadClientIntegration { } public async pauseQueueAsync() { - const client = this.getClient(); + const client = await this.getClientAsync(); const ids = (await client.listTorrents()).arguments.torrents.map(({ hashString }) => hashString); - await this.getClient().pauseTorrent(ids); + await client.pauseTorrent(ids); } public async pauseItemAsync({ id }: DownloadClientItem): Promise { - await this.getClient().pauseTorrent(id); + const client = await this.getClientAsync(); + await client.pauseTorrent(id); } public async resumeQueueAsync() { - const client = this.getClient(); + const client = await this.getClientAsync(); const ids = (await client.listTorrents()).arguments.torrents.map(({ hashString }) => hashString); - await this.getClient().resumeTorrent(ids); + await client.resumeTorrent(ids); } public async resumeItemAsync({ id }: DownloadClientItem): Promise { - await this.getClient().resumeTorrent(id); + const client = await this.getClientAsync(); + await client.resumeTorrent(id); } public async deleteItemAsync({ id }: DownloadClientItem, fromDisk: boolean): Promise { - await this.getClient().removeTorrent(id, fromDisk); + const client = await this.getClientAsync(); + await client.removeTorrent(id, fromDisk); } - private getClient() { + private async getClientAsync() { return new Transmission({ baseUrl: this.url("/").toString(), username: this.getSecretValue("username"), password: this.getSecretValue("password"), + dispatcher: await createCertificateAgentAsync(), }); } diff --git a/packages/integrations/src/homeassistant/homeassistant-integration.ts b/packages/integrations/src/homeassistant/homeassistant-integration.ts index 7d69d40b1..2f280002b 100644 --- a/packages/integrations/src/homeassistant/homeassistant-integration.ts +++ b/packages/integrations/src/homeassistant/homeassistant-integration.ts @@ -1,3 +1,4 @@ +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; import { logger } from "@homarr/log"; import { Integration } from "../base/integration"; @@ -7,7 +8,7 @@ export class HomeAssistantIntegration extends Integration { public async getEntityStateAsync(entityId: string) { try { const response = await this.getAsync(`/api/states/${entityId}`); - const body = (await response.json()) as unknown; + const body = await response.json(); if (!response.ok) { logger.warn(`Response did not indicate success`); return { @@ -71,7 +72,7 @@ export class HomeAssistantIntegration extends Integration { * @returns the response from the API */ private async getAsync(path: `/api/${string}`) { - return await fetch(this.url(path), { + return await fetchWithTrustedCertificatesAsync(this.url(path), { headers: this.getAuthHeaders(), }); } @@ -84,7 +85,7 @@ export class HomeAssistantIntegration extends Integration { * @returns the response from the API */ private async postAsync(path: `/api/${string}`, body: Record) { - return await fetch(this.url(path), { + return await fetchWithTrustedCertificatesAsync(this.url(path), { headers: this.getAuthHeaders(), body: JSON.stringify(body), method: "POST", diff --git a/packages/integrations/src/index.ts b/packages/integrations/src/index.ts index ea13ce13b..baa5a99b0 100644 --- a/packages/integrations/src/index.ts +++ b/packages/integrations/src/index.ts @@ -28,6 +28,9 @@ export type { HealthMonitoring } from "./interfaces/health-monitoring/healt-moni export { MediaRequestStatus } from "./interfaces/media-requests/media-request"; export type { MediaRequestList, MediaRequestStats } from "./interfaces/media-requests/media-request"; export type { StreamSession } from "./interfaces/media-server/session"; +export type { TdarrQueue } from "./interfaces/media-transcoding/queue"; +export type { TdarrPieSegment, TdarrStatistics } from "./interfaces/media-transcoding/statistics"; +export type { TdarrWorker } from "./interfaces/media-transcoding/workers"; // Schemas export { downloadClientItemSchema } from "./interfaces/downloads/download-client-items"; diff --git a/packages/integrations/src/interfaces/downloads/download-client-items.ts b/packages/integrations/src/interfaces/downloads/download-client-items.ts index 53d31b49a..7137890d8 100644 --- a/packages/integrations/src/interfaces/downloads/download-client-items.ts +++ b/packages/integrations/src/interfaces/downloads/download-client-items.ts @@ -1,4 +1,4 @@ -import type { Integration } from "@homarr/db/schema/sqlite"; +import type { Integration } from "@homarr/db/schema"; import { z } from "@homarr/validation"; const usenetQueueState = ["downloading", "queued", "paused"] as const; diff --git a/packages/integrations/src/interfaces/downloads/download-client-status.ts b/packages/integrations/src/interfaces/downloads/download-client-status.ts index d8bfc09c0..37fb290b6 100644 --- a/packages/integrations/src/interfaces/downloads/download-client-status.ts +++ b/packages/integrations/src/interfaces/downloads/download-client-status.ts @@ -1,4 +1,4 @@ -import type { Integration } from "@homarr/db/schema/sqlite"; +import type { Integration } from "@homarr/db/schema"; export interface DownloadClientStatus { /** If client is considered paused */ diff --git a/packages/integrations/src/interfaces/media-requests/media-request.ts b/packages/integrations/src/interfaces/media-requests/media-request.ts index c997e8014..7c90c15d8 100644 --- a/packages/integrations/src/interfaces/media-requests/media-request.ts +++ b/packages/integrations/src/interfaces/media-requests/media-request.ts @@ -47,6 +47,7 @@ export enum MediaRequestStatus { PendingApproval = 1, Approved = 2, Declined = 3, + Failed = 4, } export enum MediaAvailability { @@ -55,4 +56,5 @@ export enum MediaAvailability { Processing = 3, PartiallyAvailable = 4, Available = 5, + Blacklisted = 6, } diff --git a/packages/integrations/src/interfaces/media-transcoding/queue.ts b/packages/integrations/src/interfaces/media-transcoding/queue.ts new file mode 100644 index 000000000..1b85dddc9 --- /dev/null +++ b/packages/integrations/src/interfaces/media-transcoding/queue.ts @@ -0,0 +1,16 @@ +export interface TdarrQueue { + array: { + id: string; + healthCheck: string; + transcode: string; + filePath: string; + fileSize: number; + container: string; + codec: string; + resolution: string; + type: "transcode" | "health-check"; + }[]; + totalCount: number; + startIndex: number; + endIndex: number; +} diff --git a/packages/integrations/src/interfaces/media-transcoding/statistics.ts b/packages/integrations/src/interfaces/media-transcoding/statistics.ts new file mode 100644 index 000000000..f16d39ae4 --- /dev/null +++ b/packages/integrations/src/interfaces/media-transcoding/statistics.ts @@ -0,0 +1,29 @@ +export interface TdarrPieSegment { + name: string; + value: number; +} + +export interface TdarrStatistics { + totalFileCount: number; + totalTranscodeCount: number; + totalHealthCheckCount: number; + failedTranscodeCount: number; + failedHealthCheckCount: number; + stagedTranscodeCount: number; + stagedHealthCheckCount: number; + pies: { + libraryName: string; + libraryId: string; + totalFiles: number; + totalTranscodes: number; + savedSpace: number; + totalHealthChecks: number; + transcodeStatus: TdarrPieSegment[]; + healthCheckStatus: TdarrPieSegment[]; + videoCodecs: TdarrPieSegment[]; + videoContainers: TdarrPieSegment[]; + videoResolutions: TdarrPieSegment[]; + audioCodecs: TdarrPieSegment[]; + audioContainers: TdarrPieSegment[]; + }[]; +} diff --git a/packages/integrations/src/interfaces/media-transcoding/workers.ts b/packages/integrations/src/interfaces/media-transcoding/workers.ts new file mode 100644 index 000000000..9adaed716 --- /dev/null +++ b/packages/integrations/src/interfaces/media-transcoding/workers.ts @@ -0,0 +1,13 @@ +export interface TdarrWorker { + id: string; + filePath: string; + fps: number; + percentage: number; + ETA: string; + jobType: string; + status: string; + step: string; + originalSize: number; + estimatedSize: number | null; + outputSize: number | null; +} diff --git a/packages/integrations/src/jellyfin/jellyfin-integration.ts b/packages/integrations/src/jellyfin/jellyfin-integration.ts index 4a603d6c2..2e40391cb 100644 --- a/packages/integrations/src/jellyfin/jellyfin-integration.ts +++ b/packages/integrations/src/jellyfin/jellyfin-integration.ts @@ -2,6 +2,8 @@ import { Jellyfin } from "@jellyfin/sdk"; import { getSessionApi } from "@jellyfin/sdk/lib/utils/api/session-api"; import { getSystemApi } from "@jellyfin/sdk/lib/utils/api/system-api"; +import { createAxiosCertificateInstanceAsync } from "@homarr/certificates/server"; + import { Integration } from "../base/integration"; import type { StreamSession } from "../interfaces/media-server/session"; @@ -18,13 +20,13 @@ export class JellyfinIntegration extends Integration { }); public async testConnectionAsync(): Promise { - const api = this.getApi(); + const api = await this.getApiAsync(); const systemApi = getSystemApi(api); await systemApi.getPingSystem(); } public async getCurrentSessionsAsync(): Promise { - const api = this.getApi(); + const api = await this.getApiAsync(); const sessionApi = getSessionApi(api); const sessions = await sessionApi.getSessions(); @@ -59,8 +61,23 @@ export class JellyfinIntegration extends Integration { }); } - private getApi() { - const apiKey = this.getSecretValue("apiKey"); - return this.jellyfin.createApi(this.url("/").toString(), apiKey); + /** + * Constructs an ApiClient synchronously with an ApiKey or asynchronously + * with a username and password. + * @returns An instance of Api that has been authenticated + */ + private async getApiAsync() { + const httpsAgent = await createAxiosCertificateInstanceAsync(); + if (this.hasSecretValue("apiKey")) { + const apiKey = this.getSecretValue("apiKey"); + return this.jellyfin.createApi(this.url("/").toString(), apiKey, httpsAgent); + } + + const apiClient = this.jellyfin.createApi(this.url("/").toString(), undefined, httpsAgent); + // Authentication state is stored internally in the Api class, so now + // requests that require authentication can be made normally. + // see https://typescript-sdk.jellyfin.org/#usage + await apiClient.authenticateUserByName(this.getSecretValue("username"), this.getSecretValue("password")); + return apiClient; } } diff --git a/packages/integrations/src/media-organizer/lidarr/lidarr-integration.ts b/packages/integrations/src/media-organizer/lidarr/lidarr-integration.ts index b89d552ea..f48eda43b 100644 --- a/packages/integrations/src/media-organizer/lidarr/lidarr-integration.ts +++ b/packages/integrations/src/media-organizer/lidarr/lidarr-integration.ts @@ -1,3 +1,4 @@ +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; import { logger } from "@homarr/log"; import { z } from "@homarr/validation"; @@ -8,7 +9,7 @@ export class LidarrIntegration extends MediaOrganizerIntegration { public async testConnectionAsync(): Promise { await super.handleTestConnectionResponseAsync({ queryFunctionAsync: async () => { - return await fetch(this.url("/api"), { + return await fetchWithTrustedCertificatesAsync(this.url("/api"), { headers: { "X-Api-Key": super.getSecretValue("apiKey") }, }); }, @@ -28,7 +29,7 @@ export class LidarrIntegration extends MediaOrganizerIntegration { unmonitored: includeUnmonitored, }); - const response = await fetch(url, { + const response = await fetchWithTrustedCertificatesAsync(url, { headers: { "X-Api-Key": super.getSecretValue("apiKey"), }, diff --git a/packages/integrations/src/media-organizer/radarr/radarr-integration.ts b/packages/integrations/src/media-organizer/radarr/radarr-integration.ts index e11400b1e..0817fe9f6 100644 --- a/packages/integrations/src/media-organizer/radarr/radarr-integration.ts +++ b/packages/integrations/src/media-organizer/radarr/radarr-integration.ts @@ -1,3 +1,4 @@ +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; import type { AtLeastOneOf } from "@homarr/common/types"; import { logger } from "@homarr/log"; import { z } from "@homarr/validation"; @@ -20,7 +21,7 @@ export class RadarrIntegration extends MediaOrganizerIntegration { unmonitored: includeUnmonitored, }); - const response = await fetch(url, { + const response = await fetchWithTrustedCertificatesAsync(url, { headers: { "X-Api-Key": super.getSecretValue("apiKey"), }, @@ -94,7 +95,7 @@ export class RadarrIntegration extends MediaOrganizerIntegration { public async testConnectionAsync(): Promise { await super.handleTestConnectionResponseAsync({ queryFunctionAsync: async () => { - return await fetch(this.url("/api"), { + return await fetchWithTrustedCertificatesAsync(this.url("/api"), { headers: { "X-Api-Key": super.getSecretValue("apiKey") }, }); }, diff --git a/packages/integrations/src/media-organizer/readarr/readarr-integration.ts b/packages/integrations/src/media-organizer/readarr/readarr-integration.ts index 13d9eaccc..085677c74 100644 --- a/packages/integrations/src/media-organizer/readarr/readarr-integration.ts +++ b/packages/integrations/src/media-organizer/readarr/readarr-integration.ts @@ -1,3 +1,4 @@ +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; import { logger } from "@homarr/log"; import { z } from "@homarr/validation"; @@ -8,7 +9,7 @@ export class ReadarrIntegration extends MediaOrganizerIntegration { public async testConnectionAsync(): Promise { await super.handleTestConnectionResponseAsync({ queryFunctionAsync: async () => { - return await fetch(this.url("/api"), { + return await fetchWithTrustedCertificatesAsync(this.url("/api"), { headers: { "X-Api-Key": super.getSecretValue("apiKey") }, }); }, @@ -34,7 +35,7 @@ export class ReadarrIntegration extends MediaOrganizerIntegration { includeAuthor, }); - const response = await fetch(url, { + const response = await fetchWithTrustedCertificatesAsync(url, { headers: { "X-Api-Key": super.getSecretValue("apiKey"), }, diff --git a/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts b/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts index c13c65620..c9cb9393f 100644 --- a/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts +++ b/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts @@ -1,3 +1,4 @@ +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; import { logger } from "@homarr/log"; import { z } from "@homarr/validation"; @@ -21,7 +22,7 @@ export class SonarrIntegration extends MediaOrganizerIntegration { includeEpisodeImages: true, }); - const response = await fetch(url, { + const response = await fetchWithTrustedCertificatesAsync(url, { headers: { "X-Api-Key": super.getSecretValue("apiKey"), }, @@ -93,7 +94,7 @@ export class SonarrIntegration extends MediaOrganizerIntegration { public async testConnectionAsync(): Promise { await super.handleTestConnectionResponseAsync({ queryFunctionAsync: async () => { - return await fetch(this.url("/api"), { + return await fetchWithTrustedCertificatesAsync(this.url("/api"), { headers: { "X-Api-Key": super.getSecretValue("apiKey") }, }); }, diff --git a/packages/integrations/src/media-transcoding/tdarr-integration.ts b/packages/integrations/src/media-transcoding/tdarr-integration.ts new file mode 100644 index 000000000..fad62b28d --- /dev/null +++ b/packages/integrations/src/media-transcoding/tdarr-integration.ts @@ -0,0 +1,173 @@ +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; +import { z } from "@homarr/validation"; + +import { Integration } from "../base/integration"; +import type { TdarrQueue } from "../interfaces/media-transcoding/queue"; +import type { TdarrStatistics } from "../interfaces/media-transcoding/statistics"; +import type { TdarrWorker } from "../interfaces/media-transcoding/workers"; +import { getNodesResponseSchema, getStatisticsSchema, getStatusTableSchema } from "./tdarr-validation-schemas"; + +export class TdarrIntegration extends Integration { + public async testConnectionAsync(): Promise { + const url = this.url("/api/v2/status"); + const response = await fetchWithTrustedCertificatesAsync(url); + if (response.status !== 200) { + throw new Error(`Unexpected status code: ${response.status}`); + } + + await z.object({ status: z.string() }).parseAsync(await response.json()); + } + + public async getStatisticsAsync(): Promise { + const url = this.url("/api/v2/cruddb"); + const response = await fetchWithTrustedCertificatesAsync(url, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + data: { + collection: "StatisticsJSONDB", + mode: "getById", + docID: "statistics", + }, + }), + }); + + const statisticsData = await getStatisticsSchema.parseAsync(await response.json()); + + return { + totalFileCount: statisticsData.totalFileCount, + totalTranscodeCount: statisticsData.totalTranscodeCount, + totalHealthCheckCount: statisticsData.totalHealthCheckCount, + failedTranscodeCount: statisticsData.table3Count, + failedHealthCheckCount: statisticsData.table6Count, + stagedTranscodeCount: statisticsData.table1Count, + stagedHealthCheckCount: statisticsData.table4Count, + pies: statisticsData.pies.map((pie) => ({ + libraryName: pie[0], + libraryId: pie[1], + totalFiles: pie[2], + totalTranscodes: pie[3], + savedSpace: pie[4] * 1_000_000_000, // file_size is in GB, convert to bytes, + totalHealthChecks: pie[5], + transcodeStatus: pie[6], + healthCheckStatus: pie[7], + videoCodecs: pie[8], + videoContainers: pie[9], + videoResolutions: pie[10], + audioCodecs: pie[11], + audioContainers: pie[12], + })), + }; + } + + public async getWorkersAsync(): Promise { + const url = this.url("/api/v2/get-nodes"); + const response = await fetchWithTrustedCertificatesAsync(url, { + method: "GET", + headers: { "content-type": "application/json" }, + }); + + const nodesData = await getNodesResponseSchema.parseAsync(await response.json()); + const workers = Object.values(nodesData).flatMap((node) => { + return Object.values(node.workers); + }); + + return workers.map((worker) => ({ + id: worker._id, + filePath: worker.file, + fps: worker.fps, + percentage: worker.percentage, + ETA: worker.ETA, + jobType: worker.job.type, + status: worker.status, + step: worker.lastPluginDetails?.number ?? "", + originalSize: worker.originalfileSizeInGbytes * 1_000_000_000, // file_size is in GB, convert to bytes, + estimatedSize: worker.estSize ? worker.estSize * 1_000_000_000 : null, // file_size is in GB, convert to bytes, + outputSize: worker.outputFileSizeInGbytes ? worker.outputFileSizeInGbytes * 1_000_000_000 : null, // file_size is in GB, convert to bytes, + })); + } + + public async getQueueAsync(firstItemIndex: number, pageSize: number): Promise { + const transcodingQueue = await this.getTranscodingQueueAsync(firstItemIndex, pageSize); + const healthChecks = await this.getHealthCheckDataAsync(firstItemIndex, pageSize, transcodingQueue.totalCount); + + const combinedArray = [...transcodingQueue.array, ...healthChecks.array].slice(0, pageSize); + return { + array: combinedArray, + totalCount: transcodingQueue.totalCount + healthChecks.totalCount, + startIndex: firstItemIndex, + endIndex: firstItemIndex + combinedArray.length - 1, + }; + } + + private async getTranscodingQueueAsync(firstItemIndex: number, pageSize: number) { + const url = this.url("/api/v2/client/status-tables"); + const response = await fetchWithTrustedCertificatesAsync(url, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + data: { + start: firstItemIndex, + pageSize, + filters: [], + sorts: [], + opts: { table: "table1" }, + }, + }), + }); + const transcodesQueueData = await getStatusTableSchema.parseAsync(await response.json()); + + return { + array: transcodesQueueData.array.map((item) => ({ + id: item._id, + healthCheck: item.HealthCheck, + transcode: item.TranscodeDecisionMaker, + filePath: item.file, + fileSize: item.file_size * 1_000_000, // file_size is in MB, convert to bytes + container: item.container, + codec: item.video_codec_name, + resolution: item.video_resolution, + type: "transcode" as const, + })), + totalCount: transcodesQueueData.totalCount, + startIndex: firstItemIndex, + endIndex: firstItemIndex + transcodesQueueData.array.length - 1, + }; + } + + private async getHealthCheckDataAsync(firstItemIndex: number, pageSize: number, totalQueueCount: number) { + const url = this.url("/api/v2/client/status-tables"); + const response = await fetchWithTrustedCertificatesAsync(url, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + data: { + start: Math.max(firstItemIndex - totalQueueCount, 0), + pageSize, + filters: [], + sorts: [], + opts: { + table: "table4", + }, + }, + }), + }); + + const healthCheckData = await getStatusTableSchema.parseAsync(await response.json()); + + return { + array: healthCheckData.array.map((item) => ({ + id: item._id, + healthCheck: item.HealthCheck, + transcode: item.TranscodeDecisionMaker, + filePath: item.file, + fileSize: item.file_size * 1_000_000, // file_size is in MB, convert to bytes + container: item.container, + codec: item.video_codec_name, + resolution: item.video_resolution, + type: "health-check" as const, + })), + totalCount: healthCheckData.totalCount, + }; + } +} diff --git a/packages/integrations/src/media-transcoding/tdarr-validation-schemas.ts b/packages/integrations/src/media-transcoding/tdarr-validation-schemas.ts new file mode 100644 index 000000000..aabb61cc7 --- /dev/null +++ b/packages/integrations/src/media-transcoding/tdarr-validation-schemas.ts @@ -0,0 +1,118 @@ +import { z } from "@homarr/validation"; + +export const getStatisticsSchema = z.object({ + totalFileCount: z.number(), + totalTranscodeCount: z.number(), + totalHealthCheckCount: z.number(), + table3Count: z.number(), + table6Count: z.number(), + table1Count: z.number(), + table4Count: z.number(), + pies: z.array( + z.tuple([ + z.string(), // Library Name + z.string(), // Library ID + z.number(), // File count + z.number(), // Number of transcodes + z.number(), // Space saved (in GB) + z.number(), // Number of health checks + z.array( + z.object({ + // Transcode Status (Pie segments) + name: z.string(), + value: z.number(), + }), + ), + z.array( + z.object({ + // Health Status (Pie segments) + name: z.string(), + value: z.number(), + }), + ), + z.array( + z.object({ + // Video files - Codecs (Pie segments) + name: z.string(), + value: z.number(), + }), + ), + z.array( + z.object({ + // Video files - Containers (Pie segments) + name: z.string(), + value: z.number(), + }), + ), + z.array( + z.object({ + // Video files - Resolutions (Pie segments) + name: z.string(), + value: z.number(), + }), + ), + z.array( + z.object({ + // Audio files - Codecs (Pie segments) + name: z.string(), + value: z.number(), + }), + ), + z.array( + z.object({ + // Audio files - Containers (Pie segments) + name: z.string(), + value: z.number(), + }), + ), + ]), + ), +}); + +export const getNodesResponseSchema = z.record( + z.string(), + z.object({ + _id: z.string(), + nodeName: z.string(), + nodePaused: z.boolean(), + workers: z.record( + z.string(), + z.object({ + _id: z.string(), + file: z.string(), + fps: z.number(), + percentage: z.number(), + ETA: z.string(), + job: z.object({ + type: z.string(), + }), + status: z.string(), + lastPluginDetails: z + .object({ + number: z.string().optional(), + }) + .optional(), + originalfileSizeInGbytes: z.number(), + estSize: z.number().optional(), + outputFileSizeInGbytes: z.number().optional(), + workerType: z.string(), + }), + ), + }), +); + +export const getStatusTableSchema = z.object({ + array: z.array( + z.object({ + _id: z.string(), + HealthCheck: z.string(), + TranscodeDecisionMaker: z.string(), + file: z.string(), + file_size: z.number(), + container: z.string(), + video_codec_name: z.string(), + video_resolution: z.string(), + }), + ), + totalCount: z.number(), +}); diff --git a/packages/integrations/src/openmediavault/openmediavault-integration.ts b/packages/integrations/src/openmediavault/openmediavault-integration.ts index 2296ac124..8295d557e 100644 --- a/packages/integrations/src/openmediavault/openmediavault-integration.ts +++ b/packages/integrations/src/openmediavault/openmediavault-integration.ts @@ -1,3 +1,7 @@ +import type { Response } from "undici"; + +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; + import { Integration } from "../base/integration"; import { IntegrationTestConnectionError } from "../base/test-connection-error"; import type { HealthMonitoring } from "../types"; @@ -105,7 +109,7 @@ export class OpenMediaVaultIntegration extends Integration { if (!response.ok) { throw new IntegrationTestConnectionError("invalidCredentials"); } - const result = (await response.json()) as unknown; + const result = await response.json(); if (typeof result !== "object" || result === null || !("response" in result)) { throw new IntegrationTestConnectionError("invalidJson"); } @@ -117,7 +121,7 @@ export class OpenMediaVaultIntegration extends Integration { params: Record, headers: Record = {}, ): Promise { - return await fetch(this.url("/rpc.php"), { + return await fetchWithTrustedCertificatesAsync(this.url("/rpc.php"), { method: "POST", headers: { "Content-Type": "application/json", diff --git a/packages/integrations/src/overseerr/overseerr-integration.ts b/packages/integrations/src/overseerr/overseerr-integration.ts index 18101e778..a11b050ea 100644 --- a/packages/integrations/src/overseerr/overseerr-integration.ts +++ b/packages/integrations/src/overseerr/overseerr-integration.ts @@ -1,3 +1,4 @@ +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; import { logger } from "@homarr/log"; import { z } from "@homarr/validation"; @@ -6,12 +7,21 @@ import type { ISearchableIntegration } from "../base/searchable-integration"; import type { MediaRequest, RequestStats, RequestUser } from "../interfaces/media-requests/media-request"; import { MediaAvailability, MediaRequestStatus } from "../interfaces/media-requests/media-request"; +interface OverseerrSearchResult { + id: number; + name: string; + link: string; + image?: string; + text?: string; + type: Exclude["results"], undefined>[number]["mediaType"]; +} + /** * Overseerr Integration. See https://api-docs.overseerr.dev */ -export class OverseerrIntegration extends Integration implements ISearchableIntegration { - public async searchAsync(query: string): Promise<{ image?: string; name: string; link: string; text?: string }[]> { - const response = await fetch(this.url("/api/v1/search", { query }), { +export class OverseerrIntegration extends Integration implements ISearchableIntegration { + public async searchAsync(query: string) { + const response = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/search", { query }), { headers: { "X-Api-Key": this.getSecretValue("apiKey"), }, @@ -23,21 +33,60 @@ export class OverseerrIntegration extends Integration implements ISearchableInte } return schemaData.results.map((result) => ({ + id: result.id, name: "name" in result ? result.name : result.title, link: this.url(`/${result.mediaType}/${result.id}`).toString(), image: constructSearchResultImage(result), text: "overview" in result ? result.overview : undefined, + type: result.mediaType, + inLibrary: result.mediaInfo !== undefined, })); } - public async testConnectionAsync(): Promise { - const response = await fetch(this.url("/api/v1/auth/me"), { + public async getSeriesInformationAsync(mediaType: "movie" | "tv", id: number) { + const url = mediaType === "tv" ? this.url(`/api/v1/tv/${id}`) : this.url(`/api/v1/movie/${id}`); + const response = await fetchWithTrustedCertificatesAsync(url, { headers: { "X-Api-Key": this.getSecretValue("apiKey"), }, }); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const json: object = await response.json(); + return await mediaInformationSchema.parseAsync(await response.json()); + } + + /** + * Request a media. See https://api-docs.overseerr.dev/#/request/post_request + * @param mediaType The media type to request. Can be "movie" or "tv". + * @param id The Overseerr ID of the media to request. + * @param seasons A list of the seasons that should be requested. + */ + public async requestMediaAsync(mediaType: "movie" | "tv", id: number, seasons?: number[]): Promise { + const url = this.url("/api/v1/request"); + const response = await fetchWithTrustedCertificatesAsync(url, { + method: "POST", + body: JSON.stringify({ + mediaType, + mediaId: id, + seasons, + }), + headers: { + "X-Api-Key": this.getSecretValue("apiKey"), + "Content-Type": "application/json", + }, + }); + if (response.status !== 201) { + throw new Error( + `Status code ${response.status} does not match the expected status code. The request was likely not created. Response: ${await response.text()}`, + ); + } + } + + public async testConnectionAsync(): Promise { + const response = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/auth/me"), { + headers: { + "X-Api-Key": this.getSecretValue("apiKey"), + }, + }); + const json = (await response.json()) as object; if (Object.keys(json).includes("id")) { return; } @@ -47,14 +96,17 @@ export class OverseerrIntegration extends Integration implements ISearchableInte public async getRequestsAsync(): Promise { //Ensure to get all pending request first - const pendingRequests = await fetch(this.url("/api/v1/request", { take: -1, filter: "pending" }), { - headers: { - "X-Api-Key": this.getSecretValue("apiKey"), + const pendingRequests = await fetchWithTrustedCertificatesAsync( + this.url("/api/v1/request", { take: -1, filter: "pending" }), + { + headers: { + "X-Api-Key": this.getSecretValue("apiKey"), + }, }, - }); + ); //Change 20 to integration setting (set to -1 for all) - const allRequests = await fetch(this.url("/api/v1/request", { take: 20 }), { + const allRequests = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/request", { take: 20 }), { headers: { "X-Api-Key": this.getSecretValue("apiKey"), }, @@ -102,7 +154,7 @@ export class OverseerrIntegration extends Integration implements ISearchableInte } public async getStatsAsync(): Promise { - const response = await fetch(this.url("/api/v1/request/count"), { + const response = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/request/count"), { headers: { "X-Api-Key": this.getSecretValue("apiKey"), }, @@ -111,7 +163,7 @@ export class OverseerrIntegration extends Integration implements ISearchableInte } public async getUsersAsync(): Promise { - const response = await fetch(this.url("/api/v1/user", { take: -1 }), { + const response = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/user", { take: -1 }), { headers: { "X-Api-Key": this.getSecretValue("apiKey"), }, @@ -128,7 +180,7 @@ export class OverseerrIntegration extends Integration implements ISearchableInte public async approveRequestAsync(requestId: number): Promise { logger.info(`Approving media request id='${requestId}' integration='${this.integration.name}'`); - await fetch(this.url(`/api/v1/request/${requestId}/approve`), { + await fetchWithTrustedCertificatesAsync(this.url(`/api/v1/request/${requestId}/approve`), { method: "POST", headers: { "X-Api-Key": this.getSecretValue("apiKey"), @@ -146,7 +198,7 @@ export class OverseerrIntegration extends Integration implements ISearchableInte public async declineRequestAsync(requestId: number): Promise { logger.info(`Declining media request id='${requestId}' integration='${this.integration.name}'`); - await fetch(this.url(`/api/v1/request/${requestId}/decline`), { + await fetchWithTrustedCertificatesAsync(this.url(`/api/v1/request/${requestId}/decline`), { method: "POST", headers: { "X-Api-Key": this.getSecretValue("apiKey"), @@ -163,7 +215,7 @@ export class OverseerrIntegration extends Integration implements ISearchableInte } private async getItemInformationAsync(id: number, type: MediaRequest["type"]): Promise { - const response = await fetch(this.url(`/api/v1/${type}/${id}`), { + const response = await fetchWithTrustedCertificatesAsync(this.url(`/api/v1/${type}/${id}`), { headers: { "X-Api-Key": this.getSecretValue("apiKey"), }, @@ -220,6 +272,27 @@ interface MovieInformation { releaseDate: string; } +const mediaInformationSchema = z.union([ + z.object({ + id: z.number(), + overview: z.string(), + seasons: z.array( + z.object({ + id: z.number(), + name: z.string().min(0), + episodeCount: z.number().min(0), + }), + ), + numberOfSeasons: z.number(), + posterPath: z.string().startsWith("/"), + }), + z.object({ + id: z.number(), + overview: z.string(), + posterPath: z.string().startsWith("/"), + }), +]); + const searchSchema = z.object({ results: z .array( @@ -230,6 +303,7 @@ const searchSchema = z.object({ name: z.string(), posterPath: z.string().startsWith("/").endsWith(".jpg").nullable(), overview: z.string(), + mediaInfo: z.object({}).optional(), }), z.object({ id: z.number(), @@ -237,12 +311,14 @@ const searchSchema = z.object({ title: z.string(), posterPath: z.string().startsWith("/").endsWith(".jpg").nullable(), overview: z.string(), + mediaInfo: z.object({}).optional(), }), z.object({ id: z.number(), mediaType: z.literal("person"), name: z.string(), profilePath: z.string().startsWith("/").endsWith(".jpg").nullable(), + mediaInfo: z.object({}).optional(), }), ]), ) diff --git a/packages/integrations/src/pi-hole/pi-hole-integration.ts b/packages/integrations/src/pi-hole/pi-hole-integration.ts index 5549ab91a..45090a977 100644 --- a/packages/integrations/src/pi-hole/pi-hole-integration.ts +++ b/packages/integrations/src/pi-hole/pi-hole-integration.ts @@ -1,3 +1,5 @@ +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; + import { Integration } from "../base/integration"; import { IntegrationTestConnectionError } from "../base/test-connection-error"; import type { DnsHoleSummaryIntegration } from "../interfaces/dns-hole-summary/dns-hole-summary-integration"; @@ -7,7 +9,7 @@ import { summaryResponseSchema } from "./pi-hole-types"; export class PiHoleIntegration extends Integration implements DnsHoleSummaryIntegration { public async getSummaryAsync(): Promise { const apiKey = super.getSecretValue("apiKey"); - const response = await fetch(this.url("/admin/api.php?summaryRaw", { auth: apiKey })); + const response = await fetchWithTrustedCertificatesAsync(this.url("/admin/api.php?summaryRaw", { auth: apiKey })); if (!response.ok) { throw new Error( `Failed to fetch summary for ${this.integration.name} (${this.integration.id}): ${response.statusText}`, @@ -36,11 +38,11 @@ export class PiHoleIntegration extends Integration implements DnsHoleSummaryInte await super.handleTestConnectionResponseAsync({ queryFunctionAsync: async () => { - return await fetch(this.url("/admin/api.php?status", { auth: apiKey })); + return await fetchWithTrustedCertificatesAsync(this.url("/admin/api.php?status", { auth: apiKey })); }, handleResponseAsync: async (response) => { try { - const result = (await response.json()) as unknown; + const result = await response.json(); if (typeof result === "object" && result !== null && "status" in result) return; } catch { throw new IntegrationTestConnectionError("invalidJson"); @@ -53,7 +55,7 @@ export class PiHoleIntegration extends Integration implements DnsHoleSummaryInte public async enableAsync(): Promise { const apiKey = super.getSecretValue("apiKey"); - const response = await fetch(this.url("/admin/api.php?enable", { auth: apiKey })); + const response = await fetchWithTrustedCertificatesAsync(this.url("/admin/api.php?enable", { auth: apiKey })); if (!response.ok) { throw new Error( `Failed to enable PiHole for ${this.integration.name} (${this.integration.id}): ${response.statusText}`, @@ -64,7 +66,7 @@ export class PiHoleIntegration extends Integration implements DnsHoleSummaryInte public async disableAsync(duration?: number): Promise { const apiKey = super.getSecretValue("apiKey"); const url = this.url(`/admin/api.php?disable${duration ? `=${duration}` : ""}`, { auth: apiKey }); - const response = await fetch(url); + const response = await fetchWithTrustedCertificatesAsync(url); if (!response.ok) { throw new Error( `Failed to disable PiHole for ${this.integration.name} (${this.integration.id}): ${response.statusText}`, diff --git a/packages/integrations/src/plex/plex-integration.ts b/packages/integrations/src/plex/plex-integration.ts index d33e9457b..52d5ce189 100644 --- a/packages/integrations/src/plex/plex-integration.ts +++ b/packages/integrations/src/plex/plex-integration.ts @@ -1,5 +1,6 @@ import { parseStringPromise } from "xml2js"; +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; import { logger } from "@homarr/log"; import { Integration } from "../base/integration"; @@ -11,7 +12,7 @@ export class PlexIntegration extends Integration { public async getCurrentSessionsAsync(): Promise { const token = super.getSecretValue("apiKey"); - const response = await fetch(this.url("/status/sessions"), { + const response = await fetchWithTrustedCertificatesAsync(this.url("/status/sessions"), { headers: { "X-Plex-Token": token, }, @@ -66,7 +67,7 @@ export class PlexIntegration extends Integration { await super.handleTestConnectionResponseAsync({ queryFunctionAsync: async () => { - return await fetch(this.url("/"), { + return await fetchWithTrustedCertificatesAsync(this.url("/"), { headers: { "X-Plex-Token": token, }, diff --git a/packages/integrations/src/prowlarr/prowlarr-integration.ts b/packages/integrations/src/prowlarr/prowlarr-integration.ts index ee76a8ed1..7f11cd07a 100644 --- a/packages/integrations/src/prowlarr/prowlarr-integration.ts +++ b/packages/integrations/src/prowlarr/prowlarr-integration.ts @@ -1,3 +1,5 @@ +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; + import { Integration } from "../base/integration"; import { IntegrationTestConnectionError } from "../base/test-connection-error"; import type { Indexer } from "../interfaces/indexer-manager/indexer"; @@ -7,7 +9,7 @@ export class ProwlarrIntegration extends Integration { public async getIndexersAsync(): Promise { const apiKey = super.getSecretValue("apiKey"); - const indexerResponse = await fetch(this.url("/api/v1/indexer"), { + const indexerResponse = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/indexer"), { headers: { "X-Api-Key": apiKey, }, @@ -18,7 +20,7 @@ export class ProwlarrIntegration extends Integration { ); } - const statusResponse = await fetch(this.url("/api/v1/indexerstatus"), { + const statusResponse = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/indexerstatus"), { headers: { "X-Api-Key": apiKey, }, @@ -45,7 +47,7 @@ export class ProwlarrIntegration extends Integration { ); } - const inactiveIndexerIds = new Set(statusResult.data.map((status: { id: number }) => status.id)); + const inactiveIndexerIds = new Set(statusResult.data.map((status: { indexerId: number }) => status.indexerId)); const indexers: Indexer[] = indexersResult.data.map((indexer) => ({ id: indexer.id, @@ -60,7 +62,7 @@ export class ProwlarrIntegration extends Integration { public async testAllAsync(): Promise { const apiKey = super.getSecretValue("apiKey"); - const response = await fetch(this.url("/api/v1/indexer/testall"), { + const response = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/indexer/testall"), { headers: { "X-Api-Key": apiKey, }, @@ -78,7 +80,7 @@ export class ProwlarrIntegration extends Integration { await super.handleTestConnectionResponseAsync({ queryFunctionAsync: async () => { - return await fetch(this.url("/api"), { + return await fetchWithTrustedCertificatesAsync(this.url("/api"), { headers: { "X-Api-Key": apiKey, }, @@ -86,7 +88,7 @@ export class ProwlarrIntegration extends Integration { }, handleResponseAsync: async (response) => { try { - const result = (await response.json()) as unknown; + const result = await response.json(); if (typeof result === "object" && result !== null) return; } catch { throw new IntegrationTestConnectionError("invalidJson"); diff --git a/packages/integrations/src/prowlarr/prowlarr-types.ts b/packages/integrations/src/prowlarr/prowlarr-types.ts index 9b61f74f0..4f3288196 100644 --- a/packages/integrations/src/prowlarr/prowlarr-types.ts +++ b/packages/integrations/src/prowlarr/prowlarr-types.ts @@ -9,6 +9,6 @@ export const indexerResponseSchema = z.object({ export const statusResponseSchema = z.array( z.object({ - id: z.number(), + indexerId: z.number(), }), ); diff --git a/packages/integrations/src/proxmox/proxmox-integration.ts b/packages/integrations/src/proxmox/proxmox-integration.ts new file mode 100644 index 000000000..fceab7642 --- /dev/null +++ b/packages/integrations/src/proxmox/proxmox-integration.ts @@ -0,0 +1,125 @@ +import type { Proxmox } from "proxmox-api"; +import proxmoxApi from "proxmox-api"; + +import { fetchWithTrustedCertificatesAsync } from "@homarr/certificates/server"; +import { extractErrorMessage } from "@homarr/common"; +import { logger } from "@homarr/log"; + +import { Integration } from "../base/integration"; +import { IntegrationTestConnectionError } from "../base/test-connection-error"; +import type { + ComputeResourceBase, + LxcResource, + NodeResource, + QemuResource, + Resource, + StorageResource, +} from "./proxmox-types"; + +export class ProxmoxIntegration extends Integration { + public async testConnectionAsync(): Promise { + const proxmox = this.getPromoxApi(); + await proxmox.nodes.$get().catch((error) => { + throw new IntegrationTestConnectionError("internalServerError", extractErrorMessage(error)); + }); + } + + public async getClusterInfoAsync() { + const proxmox = this.getPromoxApi(); + const resources = await proxmox.cluster.resources.$get(); + + logger.info( + `Found ${resources.length} resources in Proxmox cluster node=${resources.filter((resource) => resource.type === "node").length} lxc=${resources.filter((resource) => resource.type === "lxc").length} qemu=${resources.filter((resource) => resource.type === "qemu").length} storage=${resources.filter((resource) => resource.type === "storage").length}`, + ); + + const mappedResources = resources.map(mapResource).filter((resource) => resource !== null); + return { + nodes: mappedResources.filter((resource): resource is NodeResource => resource.type === "node"), + lxcs: mappedResources.filter((resource): resource is LxcResource => resource.type === "lxc"), + vms: mappedResources.filter((resource): resource is QemuResource => resource.type === "qemu"), + storages: mappedResources.filter((resource): resource is StorageResource => resource.type === "storage"), + }; + } + + private getPromoxApi() { + return proxmoxApi({ + host: this.url("/").host, + tokenID: `${this.getSecretValue("username")}@${this.getSecretValue("realm")}!${this.getSecretValue("tokenId")}`, + tokenSecret: this.getSecretValue("apiKey"), + fetch: fetchWithTrustedCertificatesAsync, + }); + } +} + +const mapResource = (resource: Proxmox.clusterResourcesResources): Resource | null => { + switch (resource.type) { + case "node": + return mapNodeResource(resource); + case "lxc": + case "qemu": + return mapVmResource(resource); + case "storage": + return mapStorageResource(resource); + } + + return null; +}; + +const mapComputeResource = (resource: Proxmox.clusterResourcesResources): Omit, "type"> => { + return { + cpu: { + utilization: resource.cpu ?? 0, + cores: resource.maxcpu ?? 0, + }, + memory: { + used: resource.mem ?? 0, + total: resource.maxmem ?? 0, + }, + storage: { + used: resource.disk ?? 0, + total: resource.maxdisk ?? 0, + read: (resource.diskread as number | null) ?? null, + write: (resource.diskwrite as number | null) ?? null, + }, + network: { + in: (resource.netin as number | null) ?? null, + out: (resource.netout as number | null) ?? null, + }, + haState: resource.hastate ?? null, + isRunning: resource.status === "running" || resource.status === "online", + name: resource.name ?? "", + node: resource.node ?? "", + status: resource.status ?? (resource.type === "node" ? "offline" : "stopped"), + uptime: resource.uptime ?? 0, + }; +}; + +const mapNodeResource = (resource: Proxmox.clusterResourcesResources): NodeResource => { + return { + type: "node", + ...mapComputeResource(resource), + name: resource.node ?? "", + }; +}; + +const mapVmResource = (resource: Proxmox.clusterResourcesResources): LxcResource | QemuResource => { + return { + type: resource.type as "lxc" | "qemu", + vmId: resource.vmid ?? 0, + ...mapComputeResource(resource), + }; +}; + +const mapStorageResource = (resource: Proxmox.clusterResourcesResources): StorageResource => { + return { + type: "storage", + name: resource.storage ?? "", + node: resource.node ?? "", + isRunning: resource.status === "available", + status: resource.status ?? "offline", + storagePlugin: resource.storage ?? "", + total: resource.maxdisk ?? 0, + used: resource.disk ?? 0, + isShared: resource.shared === 1, + }; +}; diff --git a/packages/integrations/src/proxmox/proxmox-types.ts b/packages/integrations/src/proxmox/proxmox-types.ts new file mode 100644 index 000000000..af0db647b --- /dev/null +++ b/packages/integrations/src/proxmox/proxmox-types.ts @@ -0,0 +1,57 @@ +interface ResourceBase { + type: TType; + name: string; + node: string; + isRunning: boolean; + status: string; +} + +export interface ComputeResourceBase extends ResourceBase { + cpu: { + utilization: number; // previously cpu (0-1) + cores: number; // previously cpuCores + }; + memory: { + used: number; // previously mem + total: number; // previously maxMem + }; + storage: { + used: number; // previously disk + total: number; // previously maxDisk + read: number | null; // previously diskRead + write: number | null; // previously diskWrite + }; + network: { + in: number | null; // previously netIn + out: number | null; // previously netOut + }; + uptime: number; // expressed in seconds + haState: string | null; // HA service status (for HA managed VMs). +} + +export type NodeResource = ComputeResourceBase<"node">; + +export interface LxcResource extends ComputeResourceBase<"lxc"> { + vmId: number; +} + +export interface QemuResource extends ComputeResourceBase<"qemu"> { + vmId: number; +} + +export interface StorageResource extends ResourceBase<"storage"> { + storagePlugin: string; + used: number; // previously disk + total: number; // previously maxDisk + isShared: boolean; // previously storageShared +} + +export type ComputeResource = NodeResource | LxcResource | QemuResource; +export type Resource = ComputeResource | StorageResource; + +export interface ProxmoxClusterInfo { + nodes: NodeResource[]; + lxcs: LxcResource[]; + vms: QemuResource[]; + storages: StorageResource[]; +} diff --git a/packages/integrations/src/types.ts b/packages/integrations/src/types.ts index 2c1f72c39..d3760cadb 100644 --- a/packages/integrations/src/types.ts +++ b/packages/integrations/src/types.ts @@ -6,3 +6,4 @@ export * from "./interfaces/media-requests/media-request"; export * from "./pi-hole/pi-hole-types"; export * from "./base/searchable-integration"; export * from "./homeassistant/homeassistant-types"; +export * from "./proxmox/proxmox-types"; diff --git a/packages/integrations/test/base.spec.ts b/packages/integrations/test/base.spec.ts index 9ef1f3861..e58ea5208 100644 --- a/packages/integrations/test/base.spec.ts +++ b/packages/integrations/test/base.spec.ts @@ -1,3 +1,4 @@ +import { Response } from "undici"; import { describe, expect, test } from "vitest"; import { IntegrationTestConnectionError } from "../src"; diff --git a/packages/integrations/test/nzbget.spec.ts b/packages/integrations/test/nzbget.spec.ts index b19b39d71..c30008a99 100644 --- a/packages/integrations/test/nzbget.spec.ts +++ b/packages/integrations/test/nzbget.spec.ts @@ -1,3 +1,4 @@ +import { readFile } from "fs/promises"; import { join } from "path"; import type { StartedTestContainer } from "testcontainers"; import { GenericContainer, getContainerRuntimeClient, ImageName, Wait } from "testcontainers"; @@ -28,7 +29,7 @@ describe("Nzbget integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); + }, 30_000); test("Test connection should fail with wrong credentials", async () => { // Arrange @@ -43,7 +44,7 @@ describe("Nzbget integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("pauseQueueAsync should work", async () => { // Arrange @@ -60,7 +61,7 @@ describe("Nzbget integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("resumeQueueAsync should work", async () => { // Arrange @@ -80,7 +81,7 @@ describe("Nzbget integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("Items should be empty", async () => { // Arrange @@ -98,7 +99,7 @@ describe("Nzbget integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("1 Items should exist after adding one", async () => { // Arrange @@ -115,7 +116,7 @@ describe("Nzbget integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("Delete item should result in empty items", async () => { // Arrange @@ -124,16 +125,18 @@ describe("Nzbget integration", () => { const item = await nzbGetAddItemAsync(startedContainer, username, password, nzbGetIntegration); // Act - const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync(); const actAsync = async () => await nzbGetIntegration.deleteItemAsync(item, true); // Assert await expect(actAsync()).resolves.not.toThrow(); - await expect(getAsync()).resolves.toMatchObject({ items: [] }); + // NzbGet is slow and we wait for a second before querying the items. Test was flaky without this. + await new Promise((resolve) => setTimeout(resolve, 1000)); + const result = await nzbGetIntegration.getClientJobsAndStatusAsync(); + expect(result.items).toHaveLength(0); // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds*/ + }, 30_000); // Timeout of 30 seconds }); const createNzbGetContainer = () => { @@ -167,29 +170,34 @@ const nzbGetAddItemAsync = async ( password: string, integration: NzbGetIntegration, ) => { - // Add nzb file in the watch folder - await container.copyFilesToContainer([ - { - source: join(__dirname, "/volumes/usenet/test_download_100MB.nzb"), - target: "/downloads/nzb/test_download_100MB.nzb", - }, - ]); + const fileContent = await readFile(join(__dirname, "/volumes/usenet/test_download_100MB.nzb"), "base64"); // Trigger scanning of the watch folder (Only available way to add an item except "append" which is too complex and unnecessary) await fetch(`http://${container.getHost()}:${container.getMappedPort(6789)}/${username}:${password}/jsonrpc`, { method: "POST", - body: JSON.stringify({ method: "scan" }), + body: JSON.stringify({ + method: "append", + params: [ + "/downloads/nzb/test_download_100MB.nzb", // NZBFilename + fileContent, // Content + "", // Category + 0, // Priority + true, // AddToTop + false, // Paused + "random", // DupeKey + 1000, // DupeScore + "all", // DupeMode + [], // PPParameters + ], + }), }); - // Retries up to 10000 times to let NzbGet scan and process the nzb (1 retry should suffice tbh but NzbGet is slow) - for (let i = 0; i < 10000; i++) { - const { - items: [item], - } = await integration.getClientJobsAndStatusAsync(); - if (item) { - // Remove the added time because NzbGet doesn't return it properly in this specific case - const { added: _, ...itemRest } = item; - return itemRest; - } + + const { + items: [item], + } = await integration.getClientJobsAndStatusAsync(); + + if (!item) { + throw new Error("No item found"); } - // Throws if it can't find the item - throw new Error("No item found"); + + return item; }; diff --git a/packages/integrations/test/sabnzbd.spec.ts b/packages/integrations/test/sabnzbd.spec.ts index b549a8f3d..b153a2a86 100644 --- a/packages/integrations/test/sabnzbd.spec.ts +++ b/packages/integrations/test/sabnzbd.spec.ts @@ -28,7 +28,7 @@ describe("Sabnzbd integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("Test connection should fail with wrong ApiKey", async () => { // Arrange @@ -43,7 +43,7 @@ describe("Sabnzbd integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("pauseQueueAsync should work", async () => { // Arrange @@ -60,7 +60,7 @@ describe("Sabnzbd integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("resumeQueueAsync should work", async () => { // Arrange @@ -80,7 +80,7 @@ describe("Sabnzbd integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("Items should be empty", async () => { // Arrange @@ -98,7 +98,7 @@ describe("Sabnzbd integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("1 Items should exist after adding one", async () => { // Arrange @@ -115,7 +115,7 @@ describe("Sabnzbd integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("Pause item should work", async () => { // Arrange @@ -134,7 +134,7 @@ describe("Sabnzbd integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("Resume item should work", async () => { // Arrange @@ -154,7 +154,7 @@ describe("Sabnzbd integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds test("Delete item should result in empty items", async () => { // Arrange @@ -173,7 +173,7 @@ describe("Sabnzbd integration", () => { // Cleanup await startedContainer.stop(); - }, 20_000); // Timeout of 20 seconds + }, 30_000); // Timeout of 30 seconds }); const createSabnzbdContainer = () => { diff --git a/packages/log/package.json b/packages/log/package.json index 5c46e4381..4bbf90ad1 100644 --- a/packages/log/package.json +++ b/packages/log/package.json @@ -26,7 +26,7 @@ }, "prettier": "@homarr/prettier-config", "dependencies": { - "ioredis": "5.4.1", + "ioredis": "5.4.2", "superjson": "2.2.2", "winston": "3.17.0" }, @@ -34,7 +34,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/modals-collection/package.json b/packages/modals-collection/package.json index 7defa7be2..1dfe91465 100644 --- a/packages/modals-collection/package.json +++ b/packages/modals-collection/package.json @@ -27,21 +27,23 @@ "@homarr/form": "workspace:^0.1.0", "@homarr/modals": "workspace:^0.1.0", "@homarr/notifications": "workspace:^0.1.0", + "@homarr/old-import": "workspace:^0.1.0", "@homarr/old-schema": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.15.1", - "@tabler/icons-react": "^3.24.0", + "@mantine/core": "^7.16.0", + "@tabler/icons-react": "^3.28.1", "dayjs": "^1.11.13", - "next": "^14.2.20", - "react": "^19.0.0" + "next": "15.1.4", + "react": "19.0.0", + "react-dom": "19.0.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/modals-collection/src/boards/duplicate-board-modal.tsx b/packages/modals-collection/src/boards/duplicate-board-modal.tsx new file mode 100644 index 000000000..083cb716b --- /dev/null +++ b/packages/modals-collection/src/boards/duplicate-board-modal.tsx @@ -0,0 +1,96 @@ +import { Button, Group, Stack, Text, TextInput } from "@mantine/core"; + +import { clientApi } from "@homarr/api/client"; +import type { MaybePromise } from "@homarr/common/types"; +import { useZodForm } from "@homarr/form"; +import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; +import { useI18n } from "@homarr/translation/client"; +import { validation } from "@homarr/validation"; + +import { createModal } from "../../../modals/src/creator"; +import { useBoardNameStatus } from "./add-board-modal"; + +interface InnerProps { + board: { + id: string; + name: string; + }; + onSuccess: () => MaybePromise; +} + +export const DuplicateBoardModal = createModal(({ actions, innerProps }) => { + const t = useI18n(); + const form = useZodForm(validation.board.duplicate.omit({ id: true }), { + mode: "controlled", + initialValues: { + name: innerProps.board.name, + }, + }); + const boardNameStatus = useBoardNameStatus(form.values.name); + const { mutateAsync, isPending } = clientApi.board.duplicateBoard.useMutation(); + + return ( + { + // Prevent submit before name availability check + if (!boardNameStatus.canSubmit) return; + await mutateAsync( + { + ...values, + id: innerProps.board.id, + }, + { + async onSuccess() { + actions.closeModal(); + showSuccessNotification({ + title: t("board.action.duplicate.notification.success.title"), + message: t("board.action.duplicate.notification.success.message"), + }); + await innerProps.onSuccess(); + }, + onError() { + showErrorNotification({ + title: t("board.action.duplicate.notification.error.title"), + message: t("board.action.duplicate.notification.error.message"), + }); + }, + }, + ); + })} + > + + + {t("board.action.duplicate.message", { name: innerProps.board.name })} + + + + {boardNameStatus.description.icon ? : null} + {boardNameStatus.description.label} + + ) : null + } + withAsterisk + /> + + + + + + + + ); +}).withOptions({ + defaultTitle(t) { + return t("board.action.duplicate.title"); + }, +}); diff --git a/packages/modals-collection/src/boards/import-board-modal.tsx b/packages/modals-collection/src/boards/import-board-modal.tsx index 82caa0b75..e507a29f1 100644 --- a/packages/modals-collection/src/boards/import-board-modal.tsx +++ b/packages/modals-collection/src/boards/import-board-modal.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { Button, Fieldset, FileInput, Grid, Group, Radio, Stack, Switch, TextInput } from "@mantine/core"; +import { Button, FileInput, Group, Radio, Stack, TextInput } from "@mantine/core"; import { IconFileUpload } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; @@ -7,16 +7,18 @@ import { revalidatePathActionAsync } from "@homarr/common/client"; import { useZodForm } from "@homarr/form"; import { createModal } from "@homarr/modals"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; +import { OldmarrImportAppsSettings, SidebarBehaviourSelect } from "@homarr/old-import/components"; +import type { OldmarrImportConfiguration } from "@homarr/old-import/shared"; +import { oldmarrImportConfigurationSchema, superRefineJsonImportFile } from "@homarr/old-import/shared"; import { oldmarrConfigSchema } from "@homarr/old-schema"; -import { useScopedI18n } from "@homarr/translation/client"; -import { SelectWithDescription } from "@homarr/ui"; -import type { OldmarrImportConfiguration } from "@homarr/validation"; -import { oldmarrImportConfigurationSchema, superRefineJsonImportFile, z } from "@homarr/validation"; +import { useI18n, useScopedI18n } from "@homarr/translation/client"; +import { z } from "@homarr/validation"; import { useBoardNameStatus } from "./add-board-modal"; export const ImportBoardModal = createModal(({ actions }) => { const tOldImport = useScopedI18n("board.action.oldImport"); + const t = useI18n(); const tCommon = useScopedI18n("common"); const [fileValid, setFileValid] = useState(true); const form = useZodForm( @@ -30,7 +32,6 @@ export const ImportBoardModal = createModal(({ actions }) => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion file: null!, configuration: { - distinctAppsByHref: true, onlyImportApps: false, screenSize: "lg", sidebarBehaviour: "last-section", @@ -119,24 +120,7 @@ export const ImportBoardModal = createModal(({ actions }) => { label={tOldImport("form.file.label")} /> -
- - - - - - - - -
+ { - - - + + + - + + + + + + ); +}).withOptions({ + defaultTitle(t) { + return t("docker.action.addToHomarr.modal.title"); + }, +}); diff --git a/packages/modals-collection/src/docker/index.ts b/packages/modals-collection/src/docker/index.ts new file mode 100644 index 000000000..31b956245 --- /dev/null +++ b/packages/modals-collection/src/docker/index.ts @@ -0,0 +1 @@ +export { AddDockerAppToHomarrModal as AddDockerAppToHomarr } from "./add-docker-app-to-homarr"; diff --git a/packages/modals-collection/src/index.ts b/packages/modals-collection/src/index.ts index 45caf0411..30d81d892 100644 --- a/packages/modals-collection/src/index.ts +++ b/packages/modals-collection/src/index.ts @@ -1,3 +1,5 @@ export * from "./boards"; export * from "./invites"; export * from "./groups"; +export * from "./search-engines"; +export * from "./docker"; diff --git a/packages/modals-collection/src/search-engines/index.ts b/packages/modals-collection/src/search-engines/index.ts new file mode 100644 index 000000000..0ee3d7051 --- /dev/null +++ b/packages/modals-collection/src/search-engines/index.ts @@ -0,0 +1 @@ +export { RequestMediaModal } from "./request-media-modal"; diff --git a/packages/modals-collection/src/search-engines/request-media-modal.tsx b/packages/modals-collection/src/search-engines/request-media-modal.tsx new file mode 100644 index 000000000..85678e44c --- /dev/null +++ b/packages/modals-collection/src/search-engines/request-media-modal.tsx @@ -0,0 +1,119 @@ +import { useMemo } from "react"; +import { Button, Group, Image, LoadingOverlay, Stack, Text } from "@mantine/core"; +import type { MRT_ColumnDef } from "mantine-react-table"; +import { MRT_Table } from "mantine-react-table"; + +import { clientApi } from "@homarr/api/client"; +import { createModal } from "@homarr/modals"; +import { showSuccessNotification } from "@homarr/notifications"; +import { useI18n } from "@homarr/translation/client"; +import { useTranslatedMantineReactTable } from "@homarr/ui/hooks"; + +interface RequestMediaModalProps { + integrationId: string; + mediaId: number; + mediaType: "movie" | "tv"; +} + +export const RequestMediaModal = createModal(({ actions, innerProps }) => { + const { data, isPending: isPendingQuery } = clientApi.searchEngine.getMediaRequestOptions.useQuery({ + integrationId: innerProps.integrationId, + mediaId: innerProps.mediaId, + mediaType: innerProps.mediaType, + }); + + const { mutate, isPending: isPendingMutation } = clientApi.searchEngine.requestMedia.useMutation({ + onSuccess() { + actions.closeModal(); + showSuccessNotification({ + message: t("common.notification.create.success"), + }); + }, + }); + + const isPending = isPendingQuery || isPendingMutation; + const t = useI18n(); + + const columns = useMemo[]>( + () => [ + { + accessorKey: "name", + header: t("search.engine.media.request.modal.table.header.season"), + }, + { + accessorKey: "episodeCount", + header: t("search.engine.media.request.modal.table.header.episodes"), + }, + ], + [], + ); + + const table = useTranslatedMantineReactTable({ + columns, + data: data && "seasons" in data ? data.seasons : [], + enableColumnActions: false, + enableColumnFilters: false, + enablePagination: false, + enableSorting: false, + enableSelectAll: true, + enableRowSelection: true, + mantineTableProps: { + highlightOnHover: false, + striped: "odd", + withColumnBorders: true, + withRowBorders: true, + withTableBorder: true, + }, + initialState: { + density: "xs", + }, + }); + + const anySelected = Object.keys(table.getState().rowSelection).length > 0; + + const handleMutate = () => { + const selectedSeasons = table.getSelectedRowModel().rows.flatMap((row) => row.original.id); + mutate({ + integrationId: innerProps.integrationId, + mediaId: innerProps.mediaId, + mediaType: innerProps.mediaType, + seasons: selectedSeasons, + }); + }; + + return ( + + + {data && ( + + + + {data.overview} + + + )} + {innerProps.mediaType === "tv" && } + + + + + + ); +}).withOptions({ + size: "xl", +}); + +interface Season { + id: number; + name: string; + episodeCount: number; +} diff --git a/packages/modals/package.json b/packages/modals/package.json index 2b63c8fec..6b1779a7f 100644 --- a/packages/modals/package.json +++ b/packages/modals/package.json @@ -24,15 +24,15 @@ "dependencies": { "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", - "@mantine/core": "^7.15.1", - "@mantine/hooks": "^7.15.1", - "react": "^19.0.0" + "@mantine/core": "^7.16.0", + "@mantine/hooks": "^7.16.0", + "react": "19.0.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/notifications/package.json b/packages/notifications/package.json index d869f2dd7..bef90b8fa 100644 --- a/packages/notifications/package.json +++ b/packages/notifications/package.json @@ -24,14 +24,14 @@ "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/ui": "workspace:^0.1.0", - "@mantine/notifications": "^7.15.1", - "@tabler/icons-react": "^3.24.0" + "@mantine/notifications": "^7.16.0", + "@tabler/icons-react": "^3.28.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/old-import/package.json b/packages/old-import/package.json index 39f69c524..0dcbf34be 100644 --- a/packages/old-import/package.json +++ b/packages/old-import/package.json @@ -5,7 +5,11 @@ "license": "MIT", "type": "module", "exports": { - ".": "./index.ts" + ".": "./index.ts", + "./analyse": "./src/analyse/index.ts", + "./components": "./src/components/index.ts", + "./import": "./src/import/index.ts", + "./shared": "./src/shared.ts" }, "typesVersions": { "*": { @@ -25,16 +29,30 @@ "@homarr/common": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0", "@homarr/definitions": "workspace:^0.1.0", + "@homarr/form": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0", + "@homarr/modals": "workspace:^0.1.0", + "@homarr/notifications": "workspace:^0.1.0", "@homarr/old-schema": "workspace:^0.1.0", + "@homarr/translation": "workspace:^0.1.0", + "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "superjson": "2.2.2" + "@mantine/core": "^7.16.0", + "@mantine/hooks": "^7.16.0", + "adm-zip": "0.5.16", + "next": "15.1.4", + "react": "19.0.0", + "react-dom": "19.0.0", + "superjson": "2.2.2", + "zod": "^3.24.1", + "zod-form-data": "^2.0.5" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "@types/adm-zip": "0.5.7", + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/old-import/src/analyse/analyse-oldmarr-import.ts b/packages/old-import/src/analyse/analyse-oldmarr-import.ts new file mode 100644 index 000000000..0dc21ec82 --- /dev/null +++ b/packages/old-import/src/analyse/analyse-oldmarr-import.ts @@ -0,0 +1,64 @@ +import AdmZip from "adm-zip"; +import { z } from "zod"; + +import { logger } from "@homarr/log"; +import { oldmarrConfigSchema } from "@homarr/old-schema"; + +import { oldmarrImportUserSchema } from "../user-schema"; +import type { analyseOldmarrImportInputSchema } from "./input"; + +export const analyseOldmarrImportForRouterAsync = async (input: z.infer) => { + const { configs, checksum, users } = await analyseOldmarrImportAsync(input.file); + + return { + configs, + checksum, + userCount: users.length, + }; +}; + +export const analyseOldmarrImportAsync = async (file: File) => { + const arrayBuffer = await file.arrayBuffer(); + const zip = new AdmZip(Buffer.from(arrayBuffer)); + const entries = zip.getEntries(); + const configEntries = entries.filter((entry) => entry.entryName.endsWith(".json") && !entry.entryName.includes("/")); + const configs = configEntries.map((entry) => { + const result = oldmarrConfigSchema.safeParse(JSON.parse(entry.getData().toString())); + if (!result.success) { + logger.error(`Failed to parse config ${entry.entryName} with error: ${JSON.stringify(result.error)}`); + } + + return { + name: entry.name, + config: result.data ?? null, + isError: !result.success, + }; + }); + + const userEntry = entries.find((entry) => entry.entryName === "users/users.json"); + const users = parseUsers(userEntry); + + const checksum = entries + .find((entry) => entry.entryName === "checksum.txt") + ?.getData() + .toString("utf-8"); + + return { + configs, + users, + checksum, + }; +}; + +export type AnalyseResult = Awaited>; + +const parseUsers = (entry: AdmZip.IZipEntry | undefined) => { + if (!entry) return []; + + const result = z.array(oldmarrImportUserSchema).safeParse(JSON.parse(entry.getData().toString())); + if (!result.success) { + logger.error(`Failed to parse users with error: ${JSON.stringify(result.error)}`); + } + + return result.data ?? []; +}; diff --git a/packages/old-import/src/analyse/index.ts b/packages/old-import/src/analyse/index.ts new file mode 100644 index 000000000..1ec4b66e2 --- /dev/null +++ b/packages/old-import/src/analyse/index.ts @@ -0,0 +1,2 @@ +export * from "./input"; +export { analyseOldmarrImportForRouterAsync } from "./analyse-oldmarr-import"; diff --git a/packages/old-import/src/analyse/input.ts b/packages/old-import/src/analyse/input.ts new file mode 100644 index 000000000..876ca2d7e --- /dev/null +++ b/packages/old-import/src/analyse/input.ts @@ -0,0 +1,5 @@ +import { zfd } from "zod-form-data"; + +export const analyseOldmarrImportInputSchema = zfd.formData({ + file: zfd.file(), +}); diff --git a/packages/old-import/src/analyse/types.ts b/packages/old-import/src/analyse/types.ts new file mode 100644 index 000000000..691eed49a --- /dev/null +++ b/packages/old-import/src/analyse/types.ts @@ -0,0 +1,7 @@ +import type { Modify } from "@homarr/common/types"; +import type { OldmarrConfig } from "@homarr/old-schema"; + +import type { AnalyseResult } from "./analyse-oldmarr-import"; + +export type AnalyseConfig = AnalyseResult["configs"][number]; +export type ValidAnalyseConfig = Modify; diff --git a/packages/old-import/src/components/index.ts b/packages/old-import/src/components/index.ts new file mode 100644 index 000000000..98f86767b --- /dev/null +++ b/packages/old-import/src/components/index.ts @@ -0,0 +1,3 @@ +export { InitialOldmarrImport } from "./initial-oldmarr-import"; +export { SidebarBehaviourSelect } from "./shared/sidebar-behaviour-select"; +export { OldmarrImportAppsSettings } from "./shared/apps-section"; diff --git a/packages/old-import/src/components/initial-oldmarr-import.tsx b/packages/old-import/src/components/initial-oldmarr-import.tsx new file mode 100644 index 000000000..58eba33f6 --- /dev/null +++ b/packages/old-import/src/components/initial-oldmarr-import.tsx @@ -0,0 +1,112 @@ +import { useMemo, useState } from "react"; +import { Stack } from "@mantine/core"; +import SuperJSON from "superjson"; + +import { revalidatePathActionAsync } from "@homarr/common/client"; +import { useModalAction } from "@homarr/modals"; +import { boardSizes } from "@homarr/old-schema"; + +// We don't have access to the API client here, so we need to import it from the API package +// In the future we should consider having the used router also in this package +import { clientApi } from "../../../api/src/client"; +import type { AnalyseResult } from "../analyse/analyse-oldmarr-import"; +import { prepareMultipleImports } from "../prepare/prepare-multiple"; +import type { InitialOldmarrImportSettings } from "../settings"; +import { defaultSidebarBehaviour } from "../settings"; +import type { BoardSelectionMap, BoardSizeRecord } from "./initial/board-selection-card"; +import { BoardSelectionCard } from "./initial/board-selection-card"; +import { ImportSettingsCard } from "./initial/import-settings-card"; +import { ImportSummaryCard } from "./initial/import-summary-card"; +import { ImportTokenModal } from "./initial/token-modal"; + +interface InitialOldmarrImportProps { + file: File; + analyseResult: AnalyseResult; +} + +export const InitialOldmarrImport = ({ file, analyseResult }: InitialOldmarrImportProps) => { + const [boardSelections, setBoardSelections] = useState( + new Map(createDefaultSelections(analyseResult.configs)), + ); + const [settings, setSettings] = useState({ + onlyImportApps: false, + sidebarBehaviour: defaultSidebarBehaviour, + }); + + const { preparedApps, preparedBoards, preparedIntegrations } = useMemo( + () => prepareMultipleImports(analyseResult.configs, settings, boardSelections), + [analyseResult, boardSelections, settings], + ); + + const { mutateAsync, isPending } = clientApi.import.importInitialOldmarrImport.useMutation({ + async onSuccess() { + await revalidatePathActionAsync("/init"); + }, + }); + const { openModal } = useModalAction(ImportTokenModal); + + const createFormData = (token: string | null) => { + const formData = new FormData(); + formData.set("file", file); + formData.set("settings", JSON.stringify(settings)); + // Map can not be send over the wire without superjson + formData.set("boardSelections", SuperJSON.stringify(boardSelections)); + if (token) { + formData.set("token", token); + } + return formData; + }; + + const handleSubmitAsync = async () => { + if (analyseResult.checksum) { + openModal({ + checksum: analyseResult.checksum, + onSuccessAsync: async (token) => { + await mutateAsync(createFormData(token)); + }, + }); + return; + } + await mutateAsync(createFormData(null)); + }; + + return ( + + { + setSettings((settings) => ({ ...settings, [setting]: value })); + }} + /> + {settings.onlyImportApps ? null : ( + + )} + + + ); +}; + +const createDefaultSelections = (configs: AnalyseResult["configs"]) => { + return configs + .map(({ name, config }) => { + if (!config) return null; + + const shapes = config.apps.flatMap((app) => app.shape).concat(config.widgets.flatMap((widget) => widget.shape)); + const boardSizeRecord = boardSizes.reduce((acc, size) => { + const allInclude = shapes.every((shape) => Boolean(shape[size])); + acc[size] = allInclude ? true : null; + return acc; + }, {} as BoardSizeRecord); + return [name, boardSizeRecord]; + }) + .filter((selection): selection is [string, BoardSizeRecord] => Boolean(selection)); +}; diff --git a/packages/old-import/src/components/initial/board-selection-card.tsx b/packages/old-import/src/components/initial/board-selection-card.tsx new file mode 100644 index 000000000..485b0a8ec --- /dev/null +++ b/packages/old-import/src/components/initial/board-selection-card.tsx @@ -0,0 +1,156 @@ +import type { ChangeEvent } from "react"; +import { Anchor, Card, Checkbox, Group, Stack, Text } from "@mantine/core"; + +import { objectEntries, objectKeys } from "@homarr/common"; +import { boardSizes } from "@homarr/old-schema"; +import { useI18n, useScopedI18n } from "@homarr/translation/client"; + +type BoardSize = (typeof boardSizes)[number]; + +export type BoardSizeRecord = Record; +export type BoardSelectionMap = Map; + +interface BoardSelectionCardProps { + selections: BoardSelectionMap; + updateSelections: (callback: (selections: BoardSelectionMap) => BoardSelectionMap) => void; +} + +const allChecked = (map: BoardSelectionMap) => { + return [...map.values()].every((selection) => groupChecked(selection)); +}; + +const groupChecked = (selection: BoardSizeRecord) => + objectEntries(selection).every(([_, value]) => value === true || value === null); + +export const BoardSelectionCard = ({ selections, updateSelections }: BoardSelectionCardProps) => { + const tBoardSelection = useScopedI18n("init.step.import.boardSelection"); + const t = useI18n(); + const areAllChecked = allChecked(selections); + + const handleToggleAll = () => { + updateSelections((selections) => { + const updated = new Map(selections); + + [...selections.entries()].forEach(([name, selection]) => { + objectKeys(selection).forEach((size) => { + if (selection[size] === null) return; + selection[size] = !areAllChecked; + }); + + updated.set(name, selection); + }); + + return updated; + }); + }; + + const registerToggleGroup = (name: string) => (event: ChangeEvent) => { + updateSelections((selections) => { + const updated = new Map(selections); + const selection = selections.get(name); + + if (!selection) return updated; + + objectKeys(selection).forEach((size) => { + if (selection[size] === null) return; + selection[size] = event.target.checked; + }); + + updated.set(name, selection); + + return updated; + }); + }; + + const registerToggle = (name: string, size: BoardSize) => (event: ChangeEvent) => { + updateSelections((selections) => { + const updated = new Map(selections); + const selection = selections.get(name); + + if (!selection) return updated; + + selection[size] = event.target.checked; + + updated.set(name, selection); + + return updated; + }); + }; + + if (selections.size === 0) { + return null; + } + + return ( + + + + + {tBoardSelection("title", { count: selections.size })} + + {areAllChecked ? tBoardSelection("action.unselectAll") : tBoardSelection("action.selectAll")} + + + + {tBoardSelection("description")} + + + {t("board.action.oldImport.form.screenSize.description")} + + + + + {[...selections.entries()].map(([name, selection]) => ( + + + + {name} + + } + /> + + {boardSizes.map((size) => ( + + ))} + + + + + {name} + + } + /> + + {objectEntries(selection) + .filter(([_, value]) => value !== null) + .map(([size, value]) => ( + + ))} + + + + ))} + + + + ); +}; diff --git a/packages/old-import/src/components/initial/import-settings-card.tsx b/packages/old-import/src/components/initial/import-settings-card.tsx new file mode 100644 index 000000000..424fd729c --- /dev/null +++ b/packages/old-import/src/components/initial/import-settings-card.tsx @@ -0,0 +1,44 @@ +import { Card, Stack, Text } from "@mantine/core"; + +import { useScopedI18n } from "@homarr/translation/client"; + +import type { InitialOldmarrImportSettings } from "../../settings"; +import { OldmarrImportAppsSettings } from "../shared/apps-section"; +import { SidebarBehaviourSelect } from "../shared/sidebar-behaviour-select"; + +interface ImportSettingsCardProps { + settings: InitialOldmarrImportSettings; + updateSetting: ( + setting: TKey, + value: InitialOldmarrImportSettings[TKey], + ) => void; +} + +export const ImportSettingsCard = ({ settings, updateSetting }: ImportSettingsCardProps) => { + const tImportSettings = useScopedI18n("init.step.import.importSettings"); + return ( + + + + {tImportSettings("title")} + + {tImportSettings("description")} + + + + updateSetting("onlyImportApps", event.target.checked), + }} + /> + + updateSetting("sidebarBehaviour", value)} + /> + + + ); +}; diff --git a/packages/old-import/src/components/initial/import-summary-card.tsx b/packages/old-import/src/components/initial/import-summary-card.tsx new file mode 100644 index 000000000..876d1f43c --- /dev/null +++ b/packages/old-import/src/components/initial/import-summary-card.tsx @@ -0,0 +1,44 @@ +import { Button, Card, Group, Stack, Text } from "@mantine/core"; + +import { objectEntries } from "@homarr/common"; +import type { MaybePromise } from "@homarr/common/types"; +import { useScopedI18n } from "@homarr/translation/client"; + +interface ImportSummaryCardProps { + counts: { apps: number; boards: number; integrations: number; credentialUsers: number }; + loading: boolean; + onSubmit: () => MaybePromise; +} + +export const ImportSummaryCard = ({ counts, onSubmit, loading }: ImportSummaryCardProps) => { + const tSummary = useScopedI18n("init.step.import.summary"); + return ( + + + + {tSummary("title")} + + {tSummary("description")} + + + + + {objectEntries(counts).map(([key, count]) => ( + + + + {tSummary(`entities.${key}`)} + + {count} + + + ))} + + + + + + ); +}; diff --git a/packages/old-import/src/components/initial/token-modal.tsx b/packages/old-import/src/components/initial/token-modal.tsx new file mode 100644 index 000000000..a612f029c --- /dev/null +++ b/packages/old-import/src/components/initial/token-modal.tsx @@ -0,0 +1,67 @@ +import { Button, Group, PasswordInput, Stack } from "@mantine/core"; +import { z } from "zod"; + +import { useZodForm } from "@homarr/form"; +import { createModal } from "@homarr/modals"; +import { showErrorNotification } from "@homarr/notifications"; +import { useI18n, useScopedI18n } from "@homarr/translation/client"; + +// We don't have access to the API client here, so we need to import it from the API package +// In the future we should consider having the used router also in this package +import { clientApi } from "../../../../api/src/client"; + +interface InnerProps { + checksum: string; + onSuccessAsync: (token: string) => Promise; +} + +const formSchema = z.object({ + token: z.string().min(1).max(256), +}); + +export const ImportTokenModal = createModal(({ actions, innerProps }) => { + const t = useI18n(); + const tTokenModal = useScopedI18n("init.step.import.tokenModal"); + const { mutate, isPending } = clientApi.import.validateToken.useMutation(); + const form = useZodForm(formSchema, { initialValues: { token: "" } }); + + const handleSubmit = (values: z.infer) => { + mutate( + { checksum: innerProps.checksum, token: values.token }, + { + async onSuccess(isValid) { + if (isValid) { + actions.closeModal(); + await innerProps.onSuccessAsync(values.token); + } else { + showErrorNotification({ + title: tTokenModal("notification.error.title"), + message: tTokenModal("notification.error.message"), + }); + } + }, + }, + ); + }; + + return ( +
+ + + + + + + + + ); +}).withOptions({ defaultTitle: (t) => t("init.step.import.tokenModal.title") }); diff --git a/packages/old-import/src/components/shared/apps-section.tsx b/packages/old-import/src/components/shared/apps-section.tsx new file mode 100644 index 000000000..23fef2cc9 --- /dev/null +++ b/packages/old-import/src/components/shared/apps-section.tsx @@ -0,0 +1,23 @@ +import { Fieldset, Switch } from "@mantine/core"; + +import type { CheckboxProps } from "@homarr/form/types"; +import { useScopedI18n } from "@homarr/translation/client"; + +interface OldmarrImportAppsSettingsProps { + onlyImportApps: CheckboxProps; + background?: string; +} + +export const OldmarrImportAppsSettings = ({ background, onlyImportApps }: OldmarrImportAppsSettingsProps) => { + const tApps = useScopedI18n("board.action.oldImport.form.apps"); + + return ( +
+ +
+ ); +}; diff --git a/packages/old-import/src/components/shared/sidebar-behaviour-select.tsx b/packages/old-import/src/components/shared/sidebar-behaviour-select.tsx new file mode 100644 index 000000000..17a0e2c50 --- /dev/null +++ b/packages/old-import/src/components/shared/sidebar-behaviour-select.tsx @@ -0,0 +1,31 @@ +import type { InputPropsFor } from "@homarr/form/types"; +import { useScopedI18n } from "@homarr/translation/client"; +import { SelectWithDescription } from "@homarr/ui"; + +import type { SidebarBehaviour } from "../../settings"; + +export const SidebarBehaviourSelect = (props: InputPropsFor) => { + const tSidebarBehaviour = useScopedI18n("board.action.oldImport.form.sidebarBehavior"); + + return ( + (value ? props.onChange(value as SidebarBehaviour) : null)} + /> + ); +}; diff --git a/packages/old-import/src/import-apps.ts b/packages/old-import/src/import-apps.ts index 342ba682f..6f0a3f4fa 100644 --- a/packages/old-import/src/import-apps.ts +++ b/packages/old-import/src/import-apps.ts @@ -1,6 +1,6 @@ import { createId, inArray } from "@homarr/db"; import type { Database, InferInsertModel, InferSelectModel } from "@homarr/db"; -import { apps as appsTable } from "@homarr/db/schema/sqlite"; +import { apps as appsTable } from "@homarr/db/schema"; import { logger } from "@homarr/log"; import type { OldmarrApp } from "@homarr/old-schema"; diff --git a/packages/old-import/src/import-board.ts b/packages/old-import/src/import-board.ts index 9ea155929..737de5f56 100644 --- a/packages/old-import/src/import-board.ts +++ b/packages/old-import/src/import-board.ts @@ -1,12 +1,12 @@ import type { Database } from "@homarr/db"; import { createId } from "@homarr/db"; -import { boards } from "@homarr/db/schema/sqlite"; +import { boards } from "@homarr/db/schema"; import { logger } from "@homarr/log"; import type { OldmarrConfig } from "@homarr/old-schema"; -import type { OldmarrImportConfiguration } from "@homarr/validation"; import { mapColor } from "./mappers/map-colors"; import { mapColumnCount } from "./mappers/map-column-count"; +import type { OldmarrImportConfiguration } from "./settings"; export const insertBoardAsync = async (db: Database, old: OldmarrConfig, configuration: OldmarrImportConfiguration) => { logger.info(`Importing old homarr board configuration=${old.configProperties.name}`); diff --git a/packages/old-import/src/import-error.ts b/packages/old-import/src/import-error.ts index 89479aa2f..9c0fd3687 100644 --- a/packages/old-import/src/import-error.ts +++ b/packages/old-import/src/import-error.ts @@ -1,5 +1,6 @@ import type { OldmarrConfig } from "@homarr/old-schema"; -import type { OldmarrImportConfiguration } from "@homarr/validation"; + +import type { OldmarrImportConfiguration } from "./settings"; export class OldHomarrImportError extends Error { constructor(oldConfig: OldmarrConfig, cause: unknown) { diff --git a/packages/old-import/src/import-items.ts b/packages/old-import/src/import-items.ts index fab64c88e..ae4a6fad6 100644 --- a/packages/old-import/src/import-items.ts +++ b/packages/old-import/src/import-items.ts @@ -2,13 +2,13 @@ import SuperJSON from "superjson"; import type { Database } from "@homarr/db"; import { createId } from "@homarr/db"; -import { items } from "@homarr/db/schema/sqlite"; +import { items } from "@homarr/db/schema"; import { logger } from "@homarr/log"; import type { OldmarrApp, OldmarrWidget } from "@homarr/old-schema"; -import type { OldmarrImportConfiguration } from "@homarr/validation"; import type { WidgetComponentProps } from "../../widgets/src/definition"; import { OldHomarrScreenSizeError } from "./import-error"; +import type { OldmarrImportConfiguration } from "./settings"; import { mapKind } from "./widgets/definitions"; import { mapOptions } from "./widgets/options"; @@ -55,7 +55,7 @@ export const insertItemsAsync = async ( xOffset: screenSizeShape.location.x, yOffset: screenSizeShape.location.y, kind, - options: SuperJSON.stringify(mapOptions(kind, widget.properties, appsMap)), + options: SuperJSON.stringify(mapOptions(widget.type, widget.properties, appsMap)), }); logger.debug(`Inserted widget id=${widget.id} sectionId=${sectionId}`); diff --git a/packages/old-import/src/import-sections.ts b/packages/old-import/src/import-sections.ts index 1aa8afc87..4d332b87c 100644 --- a/packages/old-import/src/import-sections.ts +++ b/packages/old-import/src/import-sections.ts @@ -1,6 +1,6 @@ import { createId } from "@homarr/db"; import type { Database } from "@homarr/db"; -import { sections } from "@homarr/db/schema/sqlite"; +import { sections } from "@homarr/db/schema"; import { logger } from "@homarr/log"; import type { OldmarrConfig } from "@homarr/old-schema"; diff --git a/packages/old-import/src/import/collections/board-collection.ts b/packages/old-import/src/import/collections/board-collection.ts new file mode 100644 index 000000000..7178485d5 --- /dev/null +++ b/packages/old-import/src/import/collections/board-collection.ts @@ -0,0 +1,78 @@ +import { createId } from "@homarr/db"; +import { logger } from "@homarr/log"; + +import { fixSectionIssues } from "../../fix-section-issues"; +import { mapBoard } from "../../mappers/map-board"; +import { moveWidgetsAndAppsIfMerge } from "../../move-widgets-and-apps-merge"; +import { prepareItems } from "../../prepare/prepare-items"; +import type { prepareMultipleImports } from "../../prepare/prepare-multiple"; +import { prepareSections } from "../../prepare/prepare-sections"; +import type { InitialOldmarrImportSettings } from "../../settings"; +import { createDbInsertCollection } from "./common"; + +export const createBoardInsertCollection = ( + { preparedApps, preparedBoards }: Omit, "preparedIntegrations">, + settings: InitialOldmarrImportSettings, +) => { + const insertCollection = createDbInsertCollection(["apps", "boards", "sections", "items"]); + logger.info("Preparing boards for insert collection"); + + const appsMap = new Map( + preparedApps.flatMap(({ ids, ...app }) => { + const id = app.existingId ?? createId(); + return ids.map((oldId) => [oldId, { id, ...app }] as const); + }), + ); + + for (const app of appsMap.values()) { + // Skip duplicate apps + if (insertCollection.apps.some((appEntry) => appEntry.id === app.id)) { + continue; + } + // Skip apps that already exist in the database + if (app.existingId) { + continue; + } + + insertCollection.apps.push(app); + } + + if (settings.onlyImportApps) { + logger.info( + `Skipping boards and sections import due to onlyImportApps setting appCount=${insertCollection.apps.length}`, + ); + return insertCollection; + } + logger.debug(`Added apps to board insert collection count=${insertCollection.apps.length}`); + + preparedBoards.forEach((board) => { + const { wrappers, categories, wrapperIdsToMerge } = fixSectionIssues(board.config); + const { apps, widgets } = moveWidgetsAndAppsIfMerge(board.config, wrapperIdsToMerge, { + ...settings, + screenSize: board.size, + name: board.name, + }); + + logger.debug(`Fixed issues with sections and item positions fileName=${board.name}`); + + const mappedBoard = mapBoard(board); + logger.debug(`Mapped board fileName=${board.name} boardId=${mappedBoard.id}`); + insertCollection.boards.push(mappedBoard); + const preparedSections = prepareSections(mappedBoard.id, { wrappers, categories }); + + for (const section of preparedSections.values()) { + insertCollection.sections.push(section); + } + logger.debug(`Added sections to board insert collection count=${insertCollection.sections.length}`); + + const preparedItems = prepareItems({ apps, widgets }, board.size, appsMap, preparedSections); + preparedItems.forEach((item) => insertCollection.items.push(item)); + logger.debug(`Added items to board insert collection count=${insertCollection.items.length}`); + }); + + logger.info( + `Board collection prepared boardCount=${insertCollection.boards.length} sectionCount=${insertCollection.sections.length} itemCount=${insertCollection.items.length} appCount=${insertCollection.apps.length}`, + ); + + return insertCollection; +}; diff --git a/packages/old-import/src/import/collections/common.ts b/packages/old-import/src/import/collections/common.ts new file mode 100644 index 000000000..a7ad01da4 --- /dev/null +++ b/packages/old-import/src/import/collections/common.ts @@ -0,0 +1,43 @@ +import { objectEntries } from "@homarr/common"; +import type { Database, HomarrDatabaseMysql, InferInsertModel } from "@homarr/db"; +import * as schema from "@homarr/db/schema"; + +type TableKey = { + [K in keyof typeof schema]: (typeof schema)[K] extends { _: { brand: "Table" } } ? K : never; +}[keyof typeof schema]; + +export const createDbInsertCollection = (tablesInInsertOrder: TTableKey[]) => { + const context = tablesInInsertOrder.reduce( + (acc, key) => { + acc[key] = []; + return acc; + }, + {} as { [K in TTableKey]: InferInsertModel<(typeof schema)[K]>[] }, + ); + + return { + ...context, + insertAll: (db: Database) => { + db.transaction((transaction) => { + for (const [key, values] of objectEntries(context)) { + if (values.length >= 1) { + transaction + .insert(schema[key]) + .values(values as never) + .run(); + } + } + }); + }, + insertAllAsync: async (db: HomarrDatabaseMysql) => { + await db.transaction(async (transaction) => { + for (const [key, values] of objectEntries(context)) { + if (values.length >= 1) { + // Below is actually the mysqlSchema when the driver is mysql + await transaction.insert(schema[key] as never).values(values as never); + } + } + }); + }, + }; +}; diff --git a/packages/old-import/src/import/collections/integration-collection.ts b/packages/old-import/src/import/collections/integration-collection.ts new file mode 100644 index 000000000..1f67481dd --- /dev/null +++ b/packages/old-import/src/import/collections/integration-collection.ts @@ -0,0 +1,52 @@ +import { encryptSecret } from "@homarr/common/server"; +import { logger } from "@homarr/log"; + +import { mapAndDecryptIntegrations } from "../../mappers/map-integration"; +import type { PreparedIntegration } from "../../prepare/prepare-integrations"; +import { createDbInsertCollection } from "./common"; + +export const createIntegrationInsertCollection = ( + preparedIntegrations: PreparedIntegration[], + encryptionToken: string | null | undefined, +) => { + const insertCollection = createDbInsertCollection(["integrations", "integrationSecrets"]); + + if (preparedIntegrations.length === 0) { + return insertCollection; + } + + logger.info(`Preparing integrations for insert collection count=${preparedIntegrations.length}`); + + if (encryptionToken === null || encryptionToken === undefined) { + logger.debug("Skipping integration decryption due to missing token"); + return insertCollection; + } + + const preparedIntegrationsDecrypted = mapAndDecryptIntegrations(preparedIntegrations, encryptionToken); + + preparedIntegrationsDecrypted.forEach((integration) => { + insertCollection.integrations.push({ + id: integration.id, + kind: integration.kind, + name: integration.name, + url: integration.url, + }); + + integration.secrets + .filter((secret) => secret.value !== null) + .forEach((secret) => { + insertCollection.integrationSecrets.push({ + integrationId: integration.id, + kind: secret.field, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + value: encryptSecret(secret.value!), + }); + }); + }); + + logger.info( + `Added integrations and secrets to insert collection integrationCount=${insertCollection.integrations.length} secretCount=${insertCollection.integrationSecrets.length}`, + ); + + return insertCollection; +}; diff --git a/packages/old-import/src/import/collections/user-collection.ts b/packages/old-import/src/import/collections/user-collection.ts new file mode 100644 index 000000000..e98307590 --- /dev/null +++ b/packages/old-import/src/import/collections/user-collection.ts @@ -0,0 +1,60 @@ +import { createId } from "@homarr/db"; +import { credentialsAdminGroup } from "@homarr/definitions"; +import { logger } from "@homarr/log"; + +import { mapAndDecryptUsers } from "../../mappers/map-user"; +import type { OldmarrImportUser } from "../../user-schema"; +import { createDbInsertCollection } from "./common"; + +export const createUserInsertCollection = ( + importUsers: OldmarrImportUser[], + encryptionToken: string | null | undefined, +) => { + const insertCollection = createDbInsertCollection(["users", "groups", "groupMembers", "groupPermissions"]); + + if (importUsers.length === 0) { + return insertCollection; + } + + logger.info(`Preparing users for insert collection count=${importUsers.length}`); + + if (encryptionToken === null || encryptionToken === undefined) { + logger.debug("Skipping user decryption due to missing token"); + return insertCollection; + } + + const preparedUsers = mapAndDecryptUsers(importUsers, encryptionToken); + preparedUsers.forEach((user) => insertCollection.users.push(user)); + logger.debug(`Added users to insert collection count=${insertCollection.users.length}`); + + if (!preparedUsers.some((user) => user.isAdmin)) { + logger.warn("No admin users found, skipping admin group creation"); + return insertCollection; + } + + const adminGroupId = createId(); + insertCollection.groups.push({ + id: adminGroupId, + name: credentialsAdminGroup, + }); + + insertCollection.groupPermissions.push({ + groupId: adminGroupId, + permission: "admin", + }); + + const admins = preparedUsers.filter((user) => user.isAdmin); + + admins.forEach((user) => { + insertCollection.groupMembers.push({ + groupId: adminGroupId, + userId: user.id, + }); + }); + + logger.info( + `Added admin group and permissions to insert collection adminGroupId=${adminGroupId} adminUsersCount=${admins.length}`, + ); + + return insertCollection; +}; diff --git a/packages/old-import/src/import/import-initial-oldmarr.ts b/packages/old-import/src/import/import-initial-oldmarr.ts new file mode 100644 index 000000000..fdf1a79da --- /dev/null +++ b/packages/old-import/src/import/import-initial-oldmarr.ts @@ -0,0 +1,56 @@ +import type { z } from "zod"; + +import { Stopwatch } from "@homarr/common"; +import { handleTransactionsAsync } from "@homarr/db"; +import type { Database } from "@homarr/db"; +import { logger } from "@homarr/log"; + +import { analyseOldmarrImportAsync } from "../analyse/analyse-oldmarr-import"; +import { prepareMultipleImports } from "../prepare/prepare-multiple"; +import { createBoardInsertCollection } from "./collections/board-collection"; +import { createIntegrationInsertCollection } from "./collections/integration-collection"; +import { createUserInsertCollection } from "./collections/user-collection"; +import type { importInitialOldmarrInputSchema } from "./input"; +import { ensureValidTokenOrThrow } from "./validate-token"; + +export const importInitialOldmarrAsync = async ( + db: Database, + input: z.infer, +) => { + const stopwatch = new Stopwatch(); + const { checksum, configs, users: importUsers } = await analyseOldmarrImportAsync(input.file); + ensureValidTokenOrThrow(checksum, input.token); + + const { preparedApps, preparedBoards, preparedIntegrations } = prepareMultipleImports( + configs, + input.settings, + input.boardSelections, + ); + + logger.info("Preparing import data in insert collections for database"); + + const boardInsertCollection = createBoardInsertCollection({ preparedApps, preparedBoards }, input.settings); + const userInsertCollection = createUserInsertCollection(importUsers, input.token); + const integrationInsertCollection = createIntegrationInsertCollection(preparedIntegrations, input.token); + + logger.info("Inserting import data to database"); + + await handleTransactionsAsync(db, { + async handleAsync(db) { + await db.transaction(async (transaction) => { + await boardInsertCollection.insertAllAsync(transaction); + await userInsertCollection.insertAllAsync(transaction); + await integrationInsertCollection.insertAllAsync(transaction); + }); + }, + handleSync(db) { + db.transaction((transaction) => { + boardInsertCollection.insertAll(transaction); + userInsertCollection.insertAll(transaction); + integrationInsertCollection.insertAll(transaction); + }); + }, + }); + + logger.info(`Import successful (in ${stopwatch.getElapsedInHumanWords()})`); +}; diff --git a/packages/old-import/src/import/import-single-oldmarr.ts b/packages/old-import/src/import/import-single-oldmarr.ts new file mode 100644 index 000000000..2ca6ed4c1 --- /dev/null +++ b/packages/old-import/src/import/import-single-oldmarr.ts @@ -0,0 +1,42 @@ +import { handleTransactionsAsync, inArray } from "@homarr/db"; +import type { Database } from "@homarr/db"; +import { apps } from "@homarr/db/schema"; +import type { OldmarrConfig } from "@homarr/old-schema"; + +import { doAppsMatch } from "../prepare/prepare-apps"; +import { prepareSingleImport } from "../prepare/prepare-single"; +import type { OldmarrImportConfiguration } from "../settings"; +import { createBoardInsertCollection } from "./collections/board-collection"; + +export const importSingleOldmarrConfigAsync = async ( + db: Database, + config: OldmarrConfig, + settings: OldmarrImportConfiguration, +) => { + const { preparedApps, preparedBoards } = prepareSingleImport(config, settings); + const existingApps = await db.query.apps.findMany({ + where: inArray( + apps.href, + preparedApps.map((app) => app.href).filter((href) => href !== null), + ), + }); + + preparedApps.forEach((app) => { + const existingApp = existingApps.find((existingApp) => doAppsMatch(existingApp, app)); + if (existingApp) { + app.existingId = existingApp.id; + } + return app; + }); + + const boardInsertCollection = createBoardInsertCollection({ preparedApps, preparedBoards }, settings); + + await handleTransactionsAsync(db, { + async handleAsync(db) { + await boardInsertCollection.insertAllAsync(db); + }, + handleSync(db) { + boardInsertCollection.insertAll(db); + }, + }); +}; diff --git a/packages/old-import/src/import/index.ts b/packages/old-import/src/import/index.ts new file mode 100644 index 000000000..1c2c4cc72 --- /dev/null +++ b/packages/old-import/src/import/index.ts @@ -0,0 +1,3 @@ +export { importInitialOldmarrAsync } from "./import-initial-oldmarr"; +export * from "./input"; +export { ensureValidTokenOrThrow } from "./validate-token"; diff --git a/packages/old-import/src/import/input.ts b/packages/old-import/src/import/input.ts new file mode 100644 index 000000000..3ea7119aa --- /dev/null +++ b/packages/old-import/src/import/input.ts @@ -0,0 +1,24 @@ +import SuperJSON from "superjson"; +import { z } from "zod"; +import { zfd } from "zod-form-data"; + +import { initialOldmarrImportSettings } from "../settings"; + +const boardSelectionMapSchema = z.map( + z.string(), + z.object({ + sm: z.boolean().nullable(), + md: z.boolean().nullable(), + lg: z.boolean().nullable(), + }), +); + +export const importInitialOldmarrInputSchema = zfd.formData({ + file: zfd.file(), + settings: zfd.json(initialOldmarrImportSettings), + boardSelections: zfd.text().transform((value) => { + const map = boardSelectionMapSchema.parse(SuperJSON.parse(value)); + return map; + }), + token: zfd.text().nullable().optional(), +}); diff --git a/packages/old-import/src/import/validate-token.ts b/packages/old-import/src/import/validate-token.ts new file mode 100644 index 000000000..74e43e52e --- /dev/null +++ b/packages/old-import/src/import/validate-token.ts @@ -0,0 +1,18 @@ +import { decryptSecretWithKey } from "@homarr/common/server"; + +export const ensureValidTokenOrThrow = (checksum: string | undefined, encryptionToken: string | null | undefined) => { + if (!encryptionToken || !checksum) return; + + const [first, second] = checksum.split("\n"); + if (!first || !second) throw new Error("Malformed checksum"); + + const key = Buffer.from(encryptionToken, "hex"); + let decrypted: string; + try { + decrypted = decryptSecretWithKey(second as `${string}.${string}`, key); + } catch { + throw new Error("Invalid checksum"); + } + const isValid = decrypted === first; + if (!isValid) throw new Error("Invalid checksum"); +}; diff --git a/packages/old-import/src/index.ts b/packages/old-import/src/index.ts index aa5ad882a..d3153a189 100644 --- a/packages/old-import/src/index.ts +++ b/packages/old-import/src/index.ts @@ -1,60 +1,13 @@ import type { Database } from "@homarr/db"; import type { OldmarrConfig } from "@homarr/old-schema"; -import type { OldmarrImportConfiguration } from "@homarr/validation"; -import { fixSectionIssues } from "./fix-section-issues"; -import { insertAppsAsync } from "./import-apps"; -import { insertBoardAsync } from "./import-board"; -import { OldHomarrImportError, OldHomarrScreenSizeError } from "./import-error"; -import { insertItemsAsync } from "./import-items"; -import { insertSectionsAsync } from "./import-sections"; -import { moveWidgetsAndAppsIfMerge } from "./move-widgets-and-apps-merge"; -import type { BookmarkApp } from "./widgets/definitions/bookmark"; +import { importSingleOldmarrConfigAsync } from "./import/import-single-oldmarr"; +import type { OldmarrImportConfiguration } from "./settings"; -export const importAsync = async (db: Database, old: OldmarrConfig, configuration: OldmarrImportConfiguration) => { - const bookmarkApps = old.widgets - .filter((widget) => widget.type === "bookmark") - .map((widget) => widget.properties.items) - .flat() as BookmarkApp[]; - - if (configuration.onlyImportApps) { - await db - .transaction(async (trasaction) => { - await insertAppsAsync( - trasaction, - old.apps, - bookmarkApps, - configuration.distinctAppsByHref, - old.configProperties.name, - ); - }) - .catch((error) => { - throw new OldHomarrImportError(old, error); - }); - return; - } - - await db - .transaction(async (trasaction) => { - const { wrappers, categories, wrapperIdsToMerge } = fixSectionIssues(old); - const { apps, widgets } = moveWidgetsAndAppsIfMerge(old, wrapperIdsToMerge, configuration); - - const boardId = await insertBoardAsync(trasaction, old, configuration); - const sectionIdMaps = await insertSectionsAsync(trasaction, categories, wrappers, boardId); - const appsMap = await insertAppsAsync( - trasaction, - apps, - bookmarkApps, - configuration.distinctAppsByHref, - old.configProperties.name, - ); - await insertItemsAsync(trasaction, widgets, apps, appsMap, sectionIdMaps, configuration); - }) - .catch((error) => { - if (error instanceof OldHomarrScreenSizeError) { - throw error; - } - - throw new OldHomarrImportError(old, error); - }); +export const importOldmarrAsync = async ( + db: Database, + old: OldmarrConfig, + configuration: OldmarrImportConfiguration, +) => { + await importSingleOldmarrConfigAsync(db, old, configuration); }; diff --git a/packages/old-import/src/mappers/map-app.ts b/packages/old-import/src/mappers/map-app.ts new file mode 100644 index 000000000..3b0bc095e --- /dev/null +++ b/packages/old-import/src/mappers/map-app.ts @@ -0,0 +1,27 @@ +import type { InferSelectModel } from "@homarr/db"; +import type { apps } from "@homarr/db/schema"; +import type { OldmarrApp } from "@homarr/old-schema"; + +import type { OldmarrBookmarkDefinition } from "../widgets/definitions/bookmark"; + +export const mapOldmarrApp = (app: OldmarrApp): InferSelectModel => { + return { + id: app.id, + name: app.name, + iconUrl: app.appearance.iconUrl, + description: app.behaviour.tooltipDescription ?? null, + href: app.behaviour.externalUrl || app.url, + }; +}; + +export const mapOldmarrBookmarkApp = ( + app: OldmarrBookmarkDefinition["options"]["items"][number], +): InferSelectModel => { + return { + id: app.id, + name: app.name, + iconUrl: app.iconUrl, + description: null, + href: app.href, + }; +}; diff --git a/packages/old-import/src/mappers/map-board.ts b/packages/old-import/src/mappers/map-board.ts new file mode 100644 index 000000000..28a9dfa26 --- /dev/null +++ b/packages/old-import/src/mappers/map-board.ts @@ -0,0 +1,27 @@ +import type { InferInsertModel } from "@homarr/db"; +import { createId } from "@homarr/db"; +import type { boards } from "@homarr/db/schema"; + +import type { prepareMultipleImports } from "../prepare/prepare-multiple"; +import { mapColor } from "./map-colors"; +import { mapColumnCount } from "./map-column-count"; + +type PreparedBoard = ReturnType["preparedBoards"][number]; + +export const mapBoard = (preparedBoard: PreparedBoard): InferInsertModel => ({ + id: createId(), + name: preparedBoard.name, + backgroundImageAttachment: preparedBoard.config.settings.customization.backgroundImageAttachment, + backgroundImageUrl: preparedBoard.config.settings.customization.backgroundImageUrl, + backgroundImageRepeat: preparedBoard.config.settings.customization.backgroundImageRepeat, + backgroundImageSize: preparedBoard.config.settings.customization.backgroundImageSize, + columnCount: mapColumnCount(preparedBoard.config, preparedBoard.size), + faviconImageUrl: preparedBoard.config.settings.customization.faviconUrl, + isPublic: preparedBoard.config.settings.access.allowGuests, + logoImageUrl: preparedBoard.config.settings.customization.logoImageUrl, + pageTitle: preparedBoard.config.settings.customization.pageTitle, + metaTitle: preparedBoard.config.settings.customization.metaTitle, + opacity: preparedBoard.config.settings.customization.appOpacity, + primaryColor: mapColor(preparedBoard.config.settings.customization.colors.primary, "#fa5252"), + secondaryColor: mapColor(preparedBoard.config.settings.customization.colors.secondary, "#fd7e14"), +}); diff --git a/packages/old-import/src/mappers/map-column-count.ts b/packages/old-import/src/mappers/map-column-count.ts index 0f38a98e5..f2ac5c09c 100644 --- a/packages/old-import/src/mappers/map-column-count.ts +++ b/packages/old-import/src/mappers/map-column-count.ts @@ -1,5 +1,6 @@ import type { OldmarrConfig } from "@homarr/old-schema"; -import type { OldmarrImportConfiguration } from "@homarr/validation"; + +import type { OldmarrImportConfiguration } from "../settings"; export const mapColumnCount = (old: OldmarrConfig, screenSize: OldmarrImportConfiguration["screenSize"]) => { switch (screenSize) { diff --git a/packages/old-import/src/mappers/map-integration.ts b/packages/old-import/src/mappers/map-integration.ts new file mode 100644 index 000000000..e4274adb5 --- /dev/null +++ b/packages/old-import/src/mappers/map-integration.ts @@ -0,0 +1,60 @@ +import { decryptSecretWithKey } from "@homarr/common/server"; +import { createId } from "@homarr/db"; +import type { IntegrationKind } from "@homarr/definitions"; +import type { OldmarrIntegrationType } from "@homarr/old-schema"; + +import type { PreparedIntegration } from "../prepare/prepare-integrations"; + +export const mapIntegrationType = (type: OldmarrIntegrationType) => { + const kind = mapping[type]; + if (!kind) { + throw new Error(`Integration type ${type} is not supported yet`); + } + return kind; +}; + +const mapping: Record = { + adGuardHome: "adGuardHome", + deluge: "deluge", + homeAssistant: "homeAssistant", + jellyfin: "jellyfin", + jellyseerr: "jellyseerr", + lidarr: "lidarr", + nzbGet: "nzbGet", + openmediavault: "openmediavault", + overseerr: "overseerr", + pihole: "piHole", + prowlarr: "prowlarr", + proxmox: null, + qBittorrent: "qBittorrent", + radarr: "radarr", + readarr: "readarr", + sabnzbd: "sabNzbd", + sonarr: "sonarr", + tdarr: "tdarr", + transmission: "transmission", + plex: "plex", +}; + +export const mapAndDecryptIntegrations = ( + preparedIntegrations: PreparedIntegration[], + encryptionToken: string | null, +) => { + if (encryptionToken === null) { + return []; + } + + const key = Buffer.from(encryptionToken, "hex"); + + return preparedIntegrations.map(({ type, name, url, properties }) => ({ + id: createId(), + name, + url, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + kind: mapIntegrationType(type!), + secrets: properties.map((property) => ({ + ...property, + value: property.value ? decryptSecretWithKey(property.value as `${string}.${string}`, key) : null, + })), + })); +}; diff --git a/packages/old-import/src/mappers/map-item.ts b/packages/old-import/src/mappers/map-item.ts new file mode 100644 index 000000000..2b11118be --- /dev/null +++ b/packages/old-import/src/mappers/map-item.ts @@ -0,0 +1,93 @@ +import SuperJSON from "superjson"; + +import type { InferInsertModel } from "@homarr/db"; +import { createId } from "@homarr/db"; +import type { items } from "@homarr/db/schema"; +import { logger } from "@homarr/log"; +import type { BoardSize, OldmarrApp, OldmarrWidget } from "@homarr/old-schema"; + +import type { WidgetComponentProps } from "../../../widgets/src/definition"; +import { mapKind } from "../widgets/definitions"; +import { mapOptions } from "../widgets/options"; + +export const mapApp = ( + app: OldmarrApp, + boardSize: BoardSize, + appsMap: Map, + sectionMap: Map, +): InferInsertModel => { + if (app.area.type === "sidebar") throw new Error("Mapping app in sidebar is not supported"); + + const shapeForSize = app.shape[boardSize]; + if (!shapeForSize) { + throw new Error(`Failed to find a shape for appId='${app.id}' screenSize='${boardSize}'`); + } + + const sectionId = sectionMap.get(app.area.properties.id)?.id; + if (!sectionId) { + throw new Error(`Failed to find section for app appId='${app.id}' sectionId='${app.area.properties.id}'`); + } + + return { + id: createId(), + sectionId, + height: shapeForSize.size.height, + width: shapeForSize.size.width, + xOffset: shapeForSize.location.x, + yOffset: shapeForSize.location.y, + kind: "app", + options: SuperJSON.stringify({ + // it's safe to assume that the app exists in the map + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain + appId: appsMap.get(app.id)?.id!, + openInNewTab: app.behaviour.isOpeningNewTab, + pingEnabled: app.network.enabledStatusChecker, + showDescriptionTooltip: app.behaviour.tooltipDescription !== "", + showTitle: app.appearance.appNameStatus === "normal", + } satisfies WidgetComponentProps<"app">["options"]), + }; +}; + +export const mapWidget = ( + widget: OldmarrWidget, + boardSize: BoardSize, + appsMap: Map, + sectionMap: Map, +): InferInsertModel | null => { + if (widget.area.type === "sidebar") throw new Error("Mapping widget in sidebar is not supported"); + + const shapeForSize = widget.shape[boardSize]; + if (!shapeForSize) { + throw new Error(`Failed to find a shape for widgetId='${widget.id}' screenSize='${boardSize}'`); + } + + const kind = mapKind(widget.type); + if (!kind) { + logger.warn(`Failed to map widget type='${widget.type}'. It's no longer supported`); + return null; + } + + const sectionId = sectionMap.get(widget.area.properties.id)?.id; + if (!sectionId) { + throw new Error( + `Failed to find section for widget widgetId='${widget.id}' sectionId='${widget.area.properties.id}'`, + ); + } + + return { + id: createId(), + sectionId, + height: shapeForSize.size.height, + width: shapeForSize.size.width, + xOffset: shapeForSize.location.x, + yOffset: shapeForSize.location.y, + kind, + options: SuperJSON.stringify( + mapOptions( + widget.type, + widget.properties, + new Map([...appsMap.entries()].map(([key, value]) => [key, value.id])), + ), + ), + }; +}; diff --git a/packages/old-import/src/mappers/map-section.ts b/packages/old-import/src/mappers/map-section.ts new file mode 100644 index 000000000..e80b8969a --- /dev/null +++ b/packages/old-import/src/mappers/map-section.ts @@ -0,0 +1,24 @@ +import type { InferInsertModel } from "@homarr/db"; +import { createId } from "@homarr/db"; +import type { sections } from "@homarr/db/schema"; +import type { OldmarrCategorySection, OldmarrEmptySection } from "@homarr/old-schema"; + +export const mapCategorySection = ( + boardId: string, + category: OldmarrCategorySection, +): InferInsertModel => ({ + id: createId(), + boardId, + kind: "category", + xOffset: 0, + yOffset: category.position, + name: category.name, +}); + +export const mapEmptySection = (boardId: string, wrapper: OldmarrEmptySection): InferInsertModel => ({ + id: createId(), + boardId, + kind: "empty", + xOffset: 0, + yOffset: wrapper.position, +}); diff --git a/packages/old-import/src/mappers/map-user.ts b/packages/old-import/src/mappers/map-user.ts new file mode 100644 index 000000000..057222ec8 --- /dev/null +++ b/packages/old-import/src/mappers/map-user.ts @@ -0,0 +1,36 @@ +import { decryptSecretWithKey } from "@homarr/common/server"; +import type { InferInsertModel } from "@homarr/db"; +import { createId } from "@homarr/db"; +import type { users } from "@homarr/db/schema"; + +import type { OldmarrImportUser } from "../user-schema"; + +export const mapAndDecryptUsers = (importUsers: OldmarrImportUser[], encryptionToken: string | null) => { + if (encryptionToken === null) { + return []; + } + + const key = Buffer.from(encryptionToken, "hex"); + + return importUsers.map( + ({ + id, + password, + salt, + settings, + ...user + }): InferInsertModel & { oldId: string; isAdmin: boolean } => ({ + ...user, + oldId: id, + id: createId(), + name: user.name.toLowerCase(), + colorScheme: settings?.colorScheme === "environment" ? undefined : settings?.colorScheme, + firstDayOfWeek: settings?.firstDayOfWeek === "sunday" ? 0 : settings?.firstDayOfWeek === "monday" ? 1 : 6, + provider: "credentials", + pingIconsEnabled: settings?.replacePingWithIcons, + isAdmin: user.isAdmin || user.isOwner, + password: decryptSecretWithKey(password, key), + salt: decryptSecretWithKey(salt, key), + }), + ); +}; diff --git a/packages/old-import/src/move-widgets-and-apps-merge.ts b/packages/old-import/src/move-widgets-and-apps-merge.ts index 0305a8832..68abcb351 100644 --- a/packages/old-import/src/move-widgets-and-apps-merge.ts +++ b/packages/old-import/src/move-widgets-and-apps-merge.ts @@ -1,10 +1,10 @@ import { objectEntries } from "@homarr/common"; import { logger } from "@homarr/log"; import type { OldmarrApp, OldmarrConfig, OldmarrWidget } from "@homarr/old-schema"; -import type { OldmarrImportConfiguration } from "@homarr/validation"; import { OldHomarrScreenSizeError } from "./import-error"; import { mapColumnCount } from "./mappers/map-column-count"; +import type { OldmarrImportConfiguration } from "./settings"; export const moveWidgetsAndAppsIfMerge = ( old: OldmarrConfig, @@ -81,13 +81,26 @@ export const moveWidgetsAndAppsIfMerge = ( } if (configuration.sidebarBehaviour === "last-section") { - if (old.settings.customization.layout.enabledLeftSidebar) { + const areas = [...old.apps.map((app) => app.area), ...old.widgets.map((widget) => widget.area)]; + if ( + old.settings.customization.layout.enabledLeftSidebar || + areas.some((area) => area.type === "sidebar" && area.properties.location === "left") + ) { offset = moveWidgetsAndAppsInLeftSidebar(old, firstId, offset, configuration.screenSize); } - if (old.settings.customization.layout.enabledRightSidebar) { + if ( + old.settings.customization.layout.enabledRightSidebar || + areas.some((area) => area.type === "sidebar" && area.properties.location === "right") + ) { moveWidgetsAndAppsInRightSidebar(old, firstId, offset, configuration.screenSize); } + } else { + // Remove all widgets and apps in the sidebar + return { + apps: old.apps.filter((app) => app.area.type !== "sidebar"), + widgets: old.widgets.filter((app) => app.area.type !== "sidebar"), + }; } return { apps: old.apps, widgets: old.widgets }; diff --git a/packages/old-import/src/prepare/prepare-apps.ts b/packages/old-import/src/prepare/prepare-apps.ts new file mode 100644 index 000000000..973ea3653 --- /dev/null +++ b/packages/old-import/src/prepare/prepare-apps.ts @@ -0,0 +1,59 @@ +import type { InferSelectModel } from "@homarr/db"; +import type { apps } from "@homarr/db/schema"; +import type { OldmarrConfig } from "@homarr/old-schema"; + +import type { ValidAnalyseConfig } from "../analyse/types"; +import { mapOldmarrApp, mapOldmarrBookmarkApp } from "../mappers/map-app"; +import type { OldmarrBookmarkDefinition } from "../widgets/definitions/bookmark"; + +export type PreparedApp = Omit, "id"> & { ids: string[]; existingId?: string }; + +export const prepareApps = (analyseConfigs: ValidAnalyseConfig[]) => { + const preparedApps: PreparedApp[] = []; + + analyseConfigs.forEach(({ config }) => { + const appsFromConfig = extractAppsFromConfig(config).concat(extractBookmarkAppsFromConfig(config)); + addAppsToPreparedApps(preparedApps, appsFromConfig); + }); + + return preparedApps; +}; + +const extractAppsFromConfig = (config: OldmarrConfig) => { + return config.apps.map(mapOldmarrApp); +}; + +const extractBookmarkAppsFromConfig = (config: OldmarrConfig) => { + const bookmarkWidgets = config.widgets.filter((widget) => widget.type === "bookmark"); + return bookmarkWidgets.flatMap((widget) => + (widget.properties as OldmarrBookmarkDefinition["options"]).items.map(mapOldmarrBookmarkApp), + ); +}; + +const addAppsToPreparedApps = (preparedApps: PreparedApp[], configApps: InferSelectModel[]) => { + configApps.forEach(({ id, ...app }) => { + const existingApp = preparedApps.find((preparedApp) => doAppsMatch(preparedApp, app)); + + if (existingApp) { + existingApp.ids.push(id); + return; + } + + preparedApps.push({ + ...app, + ids: [id], + }); + }); +}; + +export const doAppsMatch = ( + app1: Omit, "id">, + app2: Omit, "id">, +) => { + return ( + app1.name === app2.name && + app1.iconUrl === app2.iconUrl && + app1.description === app2.description && + app1.href === app2.href + ); +}; diff --git a/packages/old-import/src/prepare/prepare-boards.ts b/packages/old-import/src/prepare/prepare-boards.ts new file mode 100644 index 000000000..76dc2bc2f --- /dev/null +++ b/packages/old-import/src/prepare/prepare-boards.ts @@ -0,0 +1,34 @@ +import { objectEntries } from "@homarr/common"; +import type { BoardSize } from "@homarr/old-schema"; + +import type { ValidAnalyseConfig } from "../analyse/types"; +import type { BoardSelectionMap } from "../components/initial/board-selection-card"; + +const boardSizeSuffix: Record = { + lg: "large", + md: "medium", + sm: "small", +}; + +export const createBoardName = (fileName: string, boardSize: BoardSize) => { + return `${fileName.replace(".json", "")}-${boardSizeSuffix[boardSize]}`; +}; + +export const prepareBoards = (analyseConfigs: ValidAnalyseConfig[], selections: BoardSelectionMap) => { + return analyseConfigs.flatMap(({ name, config }) => { + const selectedSizes = selections.get(name); + if (!selectedSizes) return []; + + return objectEntries(selectedSizes) + .map(([size, selected]) => { + if (!selected) return null; + + return { + name: createBoardName(name, size), + size, + config, + }; + }) + .filter((board) => board !== null); + }); +}; diff --git a/packages/old-import/src/prepare/prepare-integrations.ts b/packages/old-import/src/prepare/prepare-integrations.ts new file mode 100644 index 000000000..6d55ae3d9 --- /dev/null +++ b/packages/old-import/src/prepare/prepare-integrations.ts @@ -0,0 +1,19 @@ +import type { ValidAnalyseConfig } from "../analyse/types"; + +export type PreparedIntegration = ReturnType[number]; + +export const prepareIntegrations = (analyseConfigs: ValidAnalyseConfig[]) => { + return analyseConfigs.flatMap(({ config }) => { + return config.apps + .map((app) => + app.integration?.type + ? { + ...app.integration, + name: app.name, + url: app.url, + } + : null, + ) + .filter((integration) => integration !== null); + }); +}; diff --git a/packages/old-import/src/prepare/prepare-items.ts b/packages/old-import/src/prepare/prepare-items.ts new file mode 100644 index 000000000..e82d6043c --- /dev/null +++ b/packages/old-import/src/prepare/prepare-items.ts @@ -0,0 +1,14 @@ +import type { BoardSize, OldmarrConfig } from "@homarr/old-schema"; + +import { mapApp, mapWidget } from "../mappers/map-item"; + +export const prepareItems = ( + { apps, widgets }: Pick, + boardSize: BoardSize, + appsMap: Map, + sectionMap: Map, +) => + widgets + .map((widget) => mapWidget(widget, boardSize, appsMap, sectionMap)) + .filter((widget) => widget !== null) + .concat(apps.map((app) => mapApp(app, boardSize, appsMap, sectionMap))); diff --git a/packages/old-import/src/prepare/prepare-multiple.ts b/packages/old-import/src/prepare/prepare-multiple.ts new file mode 100644 index 000000000..860d65b75 --- /dev/null +++ b/packages/old-import/src/prepare/prepare-multiple.ts @@ -0,0 +1,25 @@ +import type { AnalyseConfig, ValidAnalyseConfig } from "../analyse/types"; +import type { BoardSelectionMap } from "../components/initial/board-selection-card"; +import type { InitialOldmarrImportSettings } from "../settings"; +import { prepareApps } from "./prepare-apps"; +import { prepareBoards } from "./prepare-boards"; +import { prepareIntegrations } from "./prepare-integrations"; + +export const prepareMultipleImports = ( + analyseConfigs: AnalyseConfig[], + settings: InitialOldmarrImportSettings, + selections: BoardSelectionMap, +) => { + const invalidConfigs = analyseConfigs.filter((item) => item.config === null); + invalidConfigs.forEach(({ name }) => { + console.warn(`Skipping import of ${name} due to error in configuration. See logs of container for more details.`); + }); + + const filteredConfigs = analyseConfigs.filter((item): item is ValidAnalyseConfig => item.config !== null); + + return { + preparedApps: prepareApps(filteredConfigs), + preparedBoards: settings.onlyImportApps ? [] : prepareBoards(filteredConfigs, selections), + preparedIntegrations: prepareIntegrations(filteredConfigs), + }; +}; diff --git a/packages/old-import/src/prepare/prepare-sections.ts b/packages/old-import/src/prepare/prepare-sections.ts new file mode 100644 index 000000000..28c8c7136 --- /dev/null +++ b/packages/old-import/src/prepare/prepare-sections.ts @@ -0,0 +1,13 @@ +import type { OldmarrConfig } from "@homarr/old-schema"; + +import { mapCategorySection, mapEmptySection } from "../mappers/map-section"; + +export const prepareSections = ( + boardId: string, + { categories, wrappers }: Pick, +) => + new Map( + categories + .map((category) => [category.id, mapCategorySection(boardId, category)] as const) + .concat(wrappers.map((wrapper) => [wrapper.id, mapEmptySection(boardId, wrapper)] as const)), + ); diff --git a/packages/old-import/src/prepare/prepare-single.ts b/packages/old-import/src/prepare/prepare-single.ts new file mode 100644 index 000000000..c762beada --- /dev/null +++ b/packages/old-import/src/prepare/prepare-single.ts @@ -0,0 +1,21 @@ +import type { OldmarrConfig } from "@homarr/old-schema"; + +import type { OldmarrImportConfiguration } from "../settings"; +import { prepareApps } from "./prepare-apps"; + +export const prepareSingleImport = (config: OldmarrConfig, settings: OldmarrImportConfiguration) => { + const validAnalyseConfigs = [{ name: settings.name, config, isError: false }]; + + return { + preparedApps: prepareApps(validAnalyseConfigs), + preparedBoards: settings.onlyImportApps + ? [] + : [ + { + name: settings.name, + size: settings.screenSize, + config, + }, + ], + }; +}; diff --git a/packages/old-import/src/settings.ts b/packages/old-import/src/settings.ts new file mode 100644 index 000000000..a0700c8a0 --- /dev/null +++ b/packages/old-import/src/settings.ts @@ -0,0 +1,63 @@ +import { z } from "zod"; +import { zfd } from "zod-form-data"; + +import { boardSizes } from "@homarr/old-schema"; +import { validation, zodEnumFromArray } from "@homarr/validation"; +import { createCustomErrorParams } from "@homarr/validation/form"; + +export const sidebarBehaviours = ["remove-items", "last-section"] as const; +export const defaultSidebarBehaviour = "last-section"; +export type SidebarBehaviour = (typeof sidebarBehaviours)[number]; + +export const oldmarrImportConfigurationSchema = z.object({ + name: validation.board.name, + onlyImportApps: z.boolean().default(false), + screenSize: zodEnumFromArray(boardSizes).default("lg"), + sidebarBehaviour: z.enum(sidebarBehaviours).default(defaultSidebarBehaviour), +}); + +export type OldmarrImportConfiguration = z.infer; + +export const initialOldmarrImportSettings = oldmarrImportConfigurationSchema.pick({ + onlyImportApps: true, + sidebarBehaviour: true, +}); + +export type InitialOldmarrImportSettings = z.infer; + +export const superRefineJsonImportFile = (value: File | null, context: z.RefinementCtx) => { + if (!value) { + return context.addIssue({ + code: "invalid_type", + expected: "object", + received: "null", + }); + } + + if (value.type !== "application/json") { + return context.addIssue({ + code: "custom", + params: createCustomErrorParams({ + key: "invalidFileType", + params: { expected: "JSON" }, + }), + }); + } + + if (value.size > 1024 * 1024) { + return context.addIssue({ + code: "custom", + params: createCustomErrorParams({ + key: "fileTooLarge", + params: { maxSize: "1 MB" }, + }), + }); + } + + return null; +}; + +export const importJsonFileSchema = zfd.formData({ + file: zfd.file().superRefine(superRefineJsonImportFile), + configuration: zfd.json(oldmarrImportConfigurationSchema), +}); diff --git a/packages/old-import/src/shared.ts b/packages/old-import/src/shared.ts new file mode 100644 index 000000000..4276a510c --- /dev/null +++ b/packages/old-import/src/shared.ts @@ -0,0 +1,2 @@ +export { importJsonFileSchema, superRefineJsonImportFile, oldmarrImportConfigurationSchema } from "./settings"; +export type { OldmarrImportConfiguration } from "./settings"; diff --git a/packages/old-import/src/user-schema.ts b/packages/old-import/src/user-schema.ts new file mode 100644 index 000000000..f7a84c917 --- /dev/null +++ b/packages/old-import/src/user-schema.ts @@ -0,0 +1,27 @@ +import { z } from "zod"; + +const regexEncryptedSchema = z.string().regex(/^[a-f0-9]+\.[a-f0-9]+$/g); + +const encryptedSchema = z.custom<`${string}.${string}`>((value) => regexEncryptedSchema.safeParse(value).success); + +export const oldmarrImportUserSchema = z.object({ + id: z.string(), + name: z.string(), + email: z.string().email().nullable(), + emailVerified: z.date().nullable(), + image: z.string().nullable(), + isAdmin: z.boolean(), + isOwner: z.boolean(), + settings: z + .object({ + colorScheme: z.enum(["environment", "light", "dark"]), + defaultBoard: z.string(), + firstDayOfWeek: z.enum(["monday", "saturday", "sunday"]), + replacePingWithIcons: z.boolean(), + }) + .nullable(), + password: encryptedSchema, + salt: encryptedSchema, +}); + +export type OldmarrImportUser = z.infer; diff --git a/packages/old-import/src/widgets/definitions/index.ts b/packages/old-import/src/widgets/definitions/index.ts index d574e0a37..2a11eb1ac 100644 --- a/packages/old-import/src/widgets/definitions/index.ts +++ b/packages/old-import/src/widgets/definitions/index.ts @@ -1,4 +1,5 @@ import { objectEntries } from "@homarr/common"; +import type { Inverse } from "@homarr/common/types"; import type { WidgetKind } from "@homarr/definitions"; import type { OldmarrBookmarkDefinition } from "./bookmark"; @@ -49,31 +50,32 @@ export type OldmarrWidgetDefinitions = | OldmarrMediaTranscodingDefinition; export const widgetKindMapping = { - app: null, // In oldmarr apps were not widgets - clock: "date", + date: "clock", calendar: "calendar", - downloads: "torrents-status", + "torrents-status": "downloads", weather: "weather", - rssFeed: "rss", - video: "video-stream", + rss: "rssFeed", + "video-stream": "video", iframe: "iframe", - mediaServer: "media-server", - dnsHoleSummary: "dns-hole-summary", - dnsHoleControls: "dns-hole-controls", + "media-server": "mediaServer", + "dns-hole-summary": "dnsHoleSummary", + "dns-hole-controls": "dnsHoleControls", notebook: "notebook", - "smartHome-entityState": "smart-home/entity-state", - "smartHome-executeAutomation": "smart-home/trigger-automation", - "mediaRequests-requestList": "media-requests-list", - "mediaRequests-requestStats": "media-requests-stats", - indexerManager: "indexer-manager", - bookmarks: "bookmark", - healthMonitoring: "health-monitoring", -} satisfies Record; -// Use null for widgets that did not exist in oldmarr -// TODO: revert assignment so that only old widgets are needed in the object, -// this can be done ones all widgets are implemented + "smart-home/entity-state": "smartHome-entityState", + "smart-home/trigger-automation": "smartHome-executeAutomation", + "media-requests-list": "mediaRequests-requestList", + "media-requests-stats": "mediaRequests-requestStats", + "indexer-manager": "indexerManager", + bookmark: "bookmarks", + "health-monitoring": "healthMonitoring", + dashdot: "healthMonitoring", + "media-transcoding": "mediaTranscoding", + dlspeed: null, + usenet: "downloads", +} satisfies Record; export type WidgetMapping = typeof widgetKindMapping; +export type InversedWidgetMapping = Inverse>; -export const mapKind = (kind: OldmarrWidgetDefinitions["id"]): WidgetKind | undefined => - objectEntries(widgetKindMapping).find(([_, value]) => value === kind)?.[0]; +export const mapKind = (kind: OldmarrWidgetDefinitions["id"]): keyof InversedWidgetMapping | null => + objectEntries(widgetKindMapping).find(([key]) => key === kind)?.[1] ?? null; diff --git a/packages/old-import/src/widgets/options.ts b/packages/old-import/src/widgets/options.ts index a95c8a5d9..6c9b44d7c 100644 --- a/packages/old-import/src/widgets/options.ts +++ b/packages/old-import/src/widgets/options.ts @@ -1,18 +1,18 @@ import { objectEntries } from "@homarr/common"; -import type { WidgetKind } from "@homarr/definitions"; import { logger } from "@homarr/log"; import type { WidgetComponentProps } from "../../../widgets/src/definition"; -import type { OldmarrWidgetDefinitions, WidgetMapping } from "./definitions"; +import { mapKind } from "./definitions"; +import type { InversedWidgetMapping, OldmarrWidgetDefinitions, WidgetMapping } from "./definitions"; // This type enforces, that for all widget mappings there is a corresponding option mapping, // each option of newmarr can be mapped from the value of the oldmarr options type OptionMapping = { - [WidgetKey in keyof WidgetMapping]: WidgetMapping[WidgetKey] extends null + [WidgetKey in keyof InversedWidgetMapping]: InversedWidgetMapping[WidgetKey] extends null ? null : { [OptionsKey in keyof WidgetComponentProps["options"]]: ( - oldOptions: Extract["options"], + oldOptions: Extract["options"], appsMap: Map, ) => WidgetComponentProps["options"][OptionsKey] | undefined; }; @@ -55,12 +55,16 @@ const optionMapping: OptionMapping = { useCustomTimezone: () => true, }, downloads: { - activeTorrentThreshold: (oldOptions) => oldOptions.speedLimitOfActiveTorrents, - applyFilterToRatio: (oldOptions) => oldOptions.displayRatioWithFilter, - categoryFilter: (oldOptions) => oldOptions.labelFilter, - filterIsWhitelist: (oldOptions) => oldOptions.labelFilterIsWhitelist, - enableRowSorting: (oldOptions) => oldOptions.rowSorting, - showCompletedTorrent: (oldOptions) => oldOptions.displayCompletedTorrents, + activeTorrentThreshold: (oldOptions) => + "speedLimitOfActiveTorrents" in oldOptions ? oldOptions.speedLimitOfActiveTorrents : undefined, + applyFilterToRatio: (oldOptions) => + "displayRatioWithFilter" in oldOptions ? oldOptions.displayRatioWithFilter : undefined, + categoryFilter: (oldOptions) => ("labelFilter" in oldOptions ? oldOptions.labelFilter : undefined), + filterIsWhitelist: (oldOptions) => + "labelFilterIsWhitelist" in oldOptions ? oldOptions.labelFilterIsWhitelist : undefined, + enableRowSorting: (oldOptions) => ("rowSorting" in oldOptions ? oldOptions.rowSorting : undefined), + showCompletedTorrent: (oldOptions) => + "displayCompletedTorrents" in oldOptions ? oldOptions.displayCompletedTorrents : undefined, columns: () => ["integration", "name", "progress", "time", "actions"], defaultSort: () => "type", descendingDefaultSort: () => false, @@ -124,41 +128,57 @@ const optionMapping: OptionMapping = { openIndexerSiteInNewTab: (oldOptions) => oldOptions.openIndexerSiteInNewTab, }, healthMonitoring: { - cpu: (oldOptions) => oldOptions.cpu, - memory: (oldOptions) => oldOptions.memory, - fahrenheit: (oldOptions) => oldOptions.fahrenheit, - fileSystem: (oldOptions) => oldOptions.fileSystem, + cpu: (oldOptions) => + "cpu" in oldOptions + ? oldOptions.cpu + : oldOptions.graphsOrder.some((graph) => graph.key === "cpu" && graph.subValues.enabled), + memory: (oldOptions) => + "memory" in oldOptions + ? oldOptions.memory + : oldOptions.graphsOrder.some((graph) => graph.key === "ram" && graph.subValues.enabled), + fahrenheit: (oldOptions) => ("fahrenheit" in oldOptions ? oldOptions.fahrenheit : undefined), + fileSystem: (oldOptions) => + "fileSystem" in oldOptions + ? oldOptions.fileSystem + : oldOptions.graphsOrder.some((graph) => graph.key === "storage" && graph.subValues.enabled), + defaultTab: (oldOptions) => ("defaultTabState" in oldOptions ? oldOptions.defaultTabState : undefined), + sectionIndicatorRequirement: (oldOptions) => + "sectionIndicatorColor" in oldOptions ? oldOptions.sectionIndicatorColor : undefined, + }, + mediaTranscoding: { + defaultView: (oldOptions) => oldOptions.defaultView, + queuePageSize: (oldOptions) => oldOptions.queuePageSize, }, - app: null, }; /** * Maps the oldmarr options to the newmarr options - * @param kind item kind to map + * @param type old widget type * @param oldOptions oldmarr options for this item * @param appsMap map of old app ids to new app ids * @returns newmarr options for this item or null if the item did not exist in oldmarr */ -export const mapOptions = ( - kind: K, - oldOptions: Extract["options"], +export const mapOptions = ( + type: K, + oldOptions: Extract["options"], appsMap: Map, ) => { - logger.debug(`Mapping old homarr options for widget kind=${kind} options=${JSON.stringify(oldOptions)}`); - if (optionMapping[kind] === null) { + logger.debug(`Mapping old homarr options for widget type=${type} options=${JSON.stringify(oldOptions)}`); + const kind = mapKind(type); + if (!kind) { return null; } const mapping = optionMapping[kind]; return objectEntries(mapping).reduce( - (acc, [key, value]) => { - const newValue = value(oldOptions as never, appsMap); - logger.debug(`Mapping old homarr option kind=${kind} key=${key as string} newValue=${newValue as string}`); + (acc, [key, value]: [string, (oldOptions: Record, appsMap: Map) => unknown]) => { + const newValue = value(oldOptions, appsMap); + logger.debug(`Mapping old homarr option kind=${kind} key=${key} newValue=${newValue as string}`); if (newValue !== undefined) { - acc[key as string] = newValue; + acc[key] = newValue; } return acc; }, {} as Record, - ) as WidgetComponentProps["options"]; + ) as WidgetComponentProps>["options"]; }; diff --git a/packages/old-schema/package.json b/packages/old-schema/package.json index dc36216f6..596778f36 100644 --- a/packages/old-schema/package.json +++ b/packages/old-schema/package.json @@ -22,13 +22,14 @@ }, "prettier": "@homarr/prettier-config", "dependencies": { + "@homarr/common": "workspace:^0.1.0", "zod": "^3.24.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/old-schema/src/app.ts b/packages/old-schema/src/app.ts index 5a4fb5421..87bedef25 100644 --- a/packages/old-schema/src/app.ts +++ b/packages/old-schema/src/app.ts @@ -47,6 +47,8 @@ const integrationSchema = z.enum([ "tdarr", ]); +export type OldmarrIntegrationType = z.infer; + const appIntegrationPropertySchema = z.object({ type: z.enum(["private", "public"]), field: z.enum(["apiKey", "password", "username"]), @@ -67,7 +69,7 @@ export const oldmarrAppSchema = z behaviour: appBehaviourSchema, network: appNetworkSchema, appearance: appAppearanceSchema, - integration: appIntegrationSchema.optional(), + integration: appIntegrationSchema.optional().nullable(), }) .and(tileBaseSchema); diff --git a/packages/old-schema/src/config.ts b/packages/old-schema/src/config.ts index 5ca103739..d120d31c7 100644 --- a/packages/old-schema/src/config.ts +++ b/packages/old-schema/src/config.ts @@ -28,3 +28,5 @@ export const oldmarrConfigSchema = z.object({ }); export type OldmarrConfig = z.infer; +export type OldmarrCategorySection = z.infer; +export type OldmarrEmptySection = z.infer; diff --git a/packages/old-schema/src/index.ts b/packages/old-schema/src/index.ts index 6b2e36d27..c328cd8e7 100644 --- a/packages/old-schema/src/index.ts +++ b/packages/old-schema/src/index.ts @@ -1,5 +1,7 @@ -export type { OldmarrConfig } from "./config"; +export type { OldmarrConfig, OldmarrCategorySection, OldmarrEmptySection } from "./config"; export { oldmarrConfigSchema } from "./config"; -export type { OldmarrApp } from "./app"; +export type { OldmarrApp, OldmarrIntegrationType } from "./app"; export type { OldmarrWidget, OldmarrWidgetKind } from "./widget"; export { oldmarrWidgetKinds } from "./widget"; +export { boardSizes } from "./tile"; +export type { BoardSize } from "./tile"; diff --git a/packages/old-schema/src/setting.ts b/packages/old-schema/src/setting.ts index 56c30c188..f9374a6f2 100644 --- a/packages/old-schema/src/setting.ts +++ b/packages/old-schema/src/setting.ts @@ -32,11 +32,17 @@ const accessSettingsSchema = z.object({ allowGuests: z.boolean(), }); -const gridstackSettingsSchema = z.object({ - columnCountSmall: z.number(), - columnCountMedium: z.number(), - columnCountLarge: z.number(), -}); +const gridstackSettingsSchema = z + .object({ + columnCountSmall: z.number(), + columnCountMedium: z.number(), + columnCountLarge: z.number(), + }) + .catch({ + columnCountSmall: 3, + columnCountMedium: 6, + columnCountLarge: 12, + }); const layoutSettingsSchema = z.object({ enabledLeftSidebar: z.boolean(), diff --git a/packages/old-schema/src/tile.ts b/packages/old-schema/src/tile.ts index f90071175..92c66d5af 100644 --- a/packages/old-schema/src/tile.ts +++ b/packages/old-schema/src/tile.ts @@ -1,5 +1,7 @@ import { z } from "zod"; +import { objectKeys } from "@homarr/common"; + const createAreaSchema = ( type: TType, propertiesSchema: TPropertiesSchema, @@ -53,3 +55,6 @@ export const tileBaseSchema = z.object({ area: areaSchema, shape: shapeSchema, }); + +export const boardSizes = objectKeys(shapeSchema._def.shape()); +export type BoardSize = (typeof boardSizes)[number]; diff --git a/packages/ping/package.json b/packages/ping/package.json index 42d81f663..b04faef1b 100644 --- a/packages/ping/package.json +++ b/packages/ping/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/redis/package.json b/packages/redis/package.json index 59b7797c6..f3024dddf 100644 --- a/packages/redis/package.json +++ b/packages/redis/package.json @@ -26,14 +26,14 @@ "@homarr/db": "workspace:^", "@homarr/definitions": "workspace:^", "@homarr/log": "workspace:^", - "ioredis": "5.4.1", + "ioredis": "5.4.2", "superjson": "2.2.2" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/redis/src/index.ts b/packages/redis/src/index.ts index d30adfccd..b752177ac 100644 --- a/packages/redis/src/index.ts +++ b/packages/redis/src/index.ts @@ -5,8 +5,10 @@ export { createItemAndIntegrationChannel, createItemChannel, createIntegrationOptionsChannel, + createWidgetOptionsChannel, createChannelWithLatestAndEvents, handshakeAsync, + createSubPubChannel, } from "./lib/channel"; export const exampleChannel = createSubPubChannel<{ message: string }>("example"); diff --git a/packages/redis/src/lib/channel.ts b/packages/redis/src/lib/channel.ts index 68664a2d7..42eb2ef13 100644 --- a/packages/redis/src/lib/channel.ts +++ b/packages/redis/src/lib/channel.ts @@ -183,6 +183,16 @@ export const createIntegrationOptionsChannel = ( return createChannelWithLatestAndEvents(channelName); }; +export const createWidgetOptionsChannel = ( + widgetKind: WidgetKind, + queryKey: string, + options: Record, +) => { + const optionsKey = hashObjectBase64(options); + const channelName = `widget:${widgetKind}:${queryKey}:options:${optionsKey}`; + return createChannelWithLatestAndEvents(channelName); +}; + export const createItemChannel = (itemId: string) => { return createChannelWithLatestAndEvents(`item:${itemId}`); }; diff --git a/packages/request-handler/package.json b/packages/request-handler/package.json index 0d9a95680..36a21b66d 100644 --- a/packages/request-handler/package.json +++ b/packages/request-handler/package.json @@ -29,6 +29,7 @@ "@homarr/log": "workspace:^0.1.0", "@homarr/redis": "workspace:^0.1.0", "dayjs": "^1.11.13", + "octokit": "^4.1.0", "pretty-print-error": "^1.1.2", "superjson": "2.2.2" }, @@ -36,7 +37,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/request-handler/src/health-monitoring.ts b/packages/request-handler/src/health-monitoring.ts index cd3b364d1..f57b9ee30 100644 --- a/packages/request-handler/src/health-monitoring.ts +++ b/packages/request-handler/src/health-monitoring.ts @@ -2,13 +2,13 @@ import dayjs from "dayjs"; import type { IntegrationKindByCategory } from "@homarr/definitions"; import { integrationCreator } from "@homarr/integrations"; -import type { HealthMonitoring } from "@homarr/integrations/types"; +import type { HealthMonitoring, ProxmoxClusterInfo } from "@homarr/integrations/types"; import { createCachedIntegrationRequestHandler } from "./lib/cached-integration-request-handler"; export const systemInfoRequestHandler = createCachedIntegrationRequestHandler< HealthMonitoring, - IntegrationKindByCategory<"healthMonitoring">, + Exclude, "proxmox">, Record >({ async requestAsync(integration, _input) { @@ -18,3 +18,16 @@ export const systemInfoRequestHandler = createCachedIntegrationRequestHandler< cacheDuration: dayjs.duration(5, "seconds"), queryKey: "systemInfo", }); + +export const clusterInfoRequestHandler = createCachedIntegrationRequestHandler< + ProxmoxClusterInfo, + "proxmox", + Record +>({ + async requestAsync(integration, _input) { + const integrationInstance = integrationCreator(integration); + return await integrationInstance.getClusterInfoAsync(); + }, + cacheDuration: dayjs.duration(5, "seconds"), + queryKey: "clusterInfo", +}); diff --git a/packages/request-handler/src/lib/cached-integration-request-handler.ts b/packages/request-handler/src/lib/cached-integration-request-handler.ts index 437e7117c..b5d25decc 100644 --- a/packages/request-handler/src/lib/cached-integration-request-handler.ts +++ b/packages/request-handler/src/lib/cached-integration-request-handler.ts @@ -1,7 +1,7 @@ import type { Duration } from "dayjs/plugin/duration"; import type { Modify } from "@homarr/common/types"; -import type { Integration, IntegrationSecret } from "@homarr/db/schema/sqlite"; +import type { Integration, IntegrationSecret } from "@homarr/db/schema"; import type { IntegrationKind } from "@homarr/definitions"; import { createIntegrationOptionsChannel } from "@homarr/redis"; diff --git a/packages/request-handler/src/lib/cached-widget-request-handler.ts b/packages/request-handler/src/lib/cached-widget-request-handler.ts new file mode 100644 index 000000000..4016bc5b4 --- /dev/null +++ b/packages/request-handler/src/lib/cached-widget-request-handler.ts @@ -0,0 +1,36 @@ +import type { Duration } from "dayjs/plugin/duration"; + +import type { WidgetKind } from "@homarr/definitions"; +import { createWidgetOptionsChannel } from "@homarr/redis"; + +import { createCachedRequestHandler } from "./cached-request-handler"; + +interface Options> { + // Unique key for this request handler + queryKey: string; + requestAsync: (input: TInput) => Promise; + cacheDuration: Duration; + widgetKind: TKind; +} + +export const createCachedWidgetRequestHandler = < + TData, + TKind extends WidgetKind, + TInput extends Record, +>( + requestHandlerOptions: Options, +) => { + return { + handler: (widgetOptions: TInput) => + createCachedRequestHandler({ + queryKey: requestHandlerOptions.queryKey, + requestAsync: async (input: TInput) => { + return await requestHandlerOptions.requestAsync(input); + }, + cacheDuration: requestHandlerOptions.cacheDuration, + createRedisChannel(input, options) { + return createWidgetOptionsChannel(requestHandlerOptions.widgetKind, options.queryKey, input); + }, + }).handler(widgetOptions), + }; +}; diff --git a/packages/request-handler/src/media-transcoding.ts b/packages/request-handler/src/media-transcoding.ts new file mode 100644 index 000000000..05446bdd6 --- /dev/null +++ b/packages/request-handler/src/media-transcoding.ts @@ -0,0 +1,24 @@ +import dayjs from "dayjs"; + +import type { IntegrationKindByCategory } from "@homarr/definitions"; +import { integrationCreator } from "@homarr/integrations"; +import type { TdarrQueue, TdarrStatistics, TdarrWorker } from "@homarr/integrations"; + +import { createCachedIntegrationRequestHandler } from "./lib/cached-integration-request-handler"; + +export const mediaTranscodingRequestHandler = createCachedIntegrationRequestHandler< + { queue: TdarrQueue; workers: TdarrWorker[]; statistics: TdarrStatistics }, + IntegrationKindByCategory<"mediaTranscoding">, + { pageOffset: number; pageSize: number } +>({ + queryKey: "mediaTranscoding", + cacheDuration: dayjs.duration(5, "minutes"), + async requestAsync(integration, input) { + const integrationInstance = integrationCreator(integration); + return { + queue: await integrationInstance.getQueueAsync(input.pageOffset, input.pageSize), + workers: await integrationInstance.getWorkersAsync(), + statistics: await integrationInstance.getStatisticsAsync(), + }; + }, +}); diff --git a/packages/request-handler/src/minecraft-server-status.ts b/packages/request-handler/src/minecraft-server-status.ts new file mode 100644 index 000000000..d2b98fcc3 --- /dev/null +++ b/packages/request-handler/src/minecraft-server-status.ts @@ -0,0 +1,35 @@ +import dayjs from "dayjs"; +import { z } from "zod"; + +import { fetchWithTimeout } from "@homarr/common"; + +import { createCachedWidgetRequestHandler } from "./lib/cached-widget-request-handler"; + +export const minecraftServerStatusRequestHandler = createCachedWidgetRequestHandler({ + queryKey: "minecraftServerStatusApiResult", + widgetKind: "minecraftServerStatus", + async requestAsync(input: { domain: string; isBedrockServer: boolean }) { + const path = `/3/${input.isBedrockServer ? "bedrock/" : ""}${input.domain}`; + + const response = await fetchWithTimeout(`https://api.mcsrvstat.us${path}`); + return responseSchema.parse(await response.json()); + }, + cacheDuration: dayjs.duration(5, "minutes"), +}); + +const responseSchema = z + .object({ + online: z.literal(false), + }) + .or( + z.object({ + online: z.literal(true), + players: z.object({ + online: z.number(), + max: z.number(), + }), + icon: z.string().optional(), + }), + ); + +export type MinecraftServerStatus = z.infer; diff --git a/packages/request-handler/src/update-checker.ts b/packages/request-handler/src/update-checker.ts new file mode 100644 index 000000000..a67eac911 --- /dev/null +++ b/packages/request-handler/src/update-checker.ts @@ -0,0 +1,59 @@ +import dayjs from "dayjs"; +import { Octokit } from "octokit"; +import { compareSemVer, isValidSemVer } from "semver-parser"; + +import { logger } from "@homarr/log"; +import { createChannelWithLatestAndEvents } from "@homarr/redis"; +import { createCachedRequestHandler } from "@homarr/request-handler/lib/cached-request-handler"; + +import packageJson from "../../../package.json"; + +export const updateCheckerRequestHandler = createCachedRequestHandler({ + queryKey: "homarr-update-checker", + cacheDuration: dayjs.duration(1, "hour"), + async requestAsync(_) { + const octokit = new Octokit(); + const releases = await octokit.rest.repos.listReleases({ + owner: "homarr-labs", + repo: "homarr", + }); + + const currentVersion = (packageJson as { version: string }).version; + const availableReleases = []; + + for (const release of releases.data) { + if (!isValidSemVer(release.tag_name)) { + logger.warn(`Unable to parse semantic tag '${release.tag_name}'. Update check might not work.`); + continue; + } + + availableReleases.push(release); + } + + const availableNewerReleases = availableReleases + .filter((release) => compareSemVer(release.tag_name, currentVersion) > 0) + .sort((releaseA, releaseB) => compareSemVer(releaseB.tag_name, releaseA.tag_name)); + if (availableReleases.length > 0) { + logger.info( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + `Update checker found a new available version: ${availableReleases[0]!.tag_name}. Current version is ${currentVersion}`, + ); + } else { + logger.debug(`Update checker did not find any available updates. Current version is ${currentVersion}`); + } + + return { + availableUpdates: availableNewerReleases.map((release) => ({ + name: release.name, + contentHtml: release.body_html, + url: release.html_url, + tagName: release.tag_name, + })), + }; + }, + createRedisChannel() { + return createChannelWithLatestAndEvents<{ + availableUpdates: { name: string | null; contentHtml?: string; url: string; tagName: string }[]; + }>("homarr:update"); + }, +}); diff --git a/packages/server-settings/package.json b/packages/server-settings/package.json index ecb5f334e..5c1f86c6f 100644 --- a/packages/server-settings/package.json +++ b/packages/server-settings/package.json @@ -29,7 +29,7 @@ "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/server-settings/src/index.ts b/packages/server-settings/src/index.ts index 779490f00..35f73699f 100644 --- a/packages/server-settings/src/index.ts +++ b/packages/server-settings/src/index.ts @@ -7,6 +7,7 @@ export const defaultServerSettingsKeys = [ "board", "appearance", "culture", + "search", ] as const; export type ServerSettingsRecord = Record<(typeof defaultServerSettingsKeys)[number], Record>; @@ -26,6 +27,7 @@ export const defaultServerSettings = { }, board: { homeBoardId: null as string | null, + mobileHomeBoardId: null as string | null, }, appearance: { defaultColorScheme: "light" as ColorScheme, @@ -33,6 +35,9 @@ export const defaultServerSettings = { culture: { defaultLocale: "en" as SupportedLanguage, }, + search: { + defaultSearchEngineId: null as string | null, + }, } satisfies ServerSettingsRecord; export type ServerSettings = typeof defaultServerSettings; diff --git a/packages/spotlight/package.json b/packages/spotlight/package.json index 856a50880..dcf9a98cd 100644 --- a/packages/spotlight/package.json +++ b/packages/spotlight/package.json @@ -32,20 +32,21 @@ "@homarr/modals-collection": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", - "@mantine/core": "^7.15.1", - "@mantine/hooks": "^7.15.1", - "@mantine/spotlight": "^7.15.1", - "@tabler/icons-react": "^3.24.0", - "jotai": "^2.10.3", - "next": "^14.2.20", - "react": "^19.0.0", + "@mantine/core": "^7.16.0", + "@mantine/hooks": "^7.16.0", + "@mantine/spotlight": "^7.16.0", + "@tabler/icons-react": "^3.28.1", + "jotai": "^2.11.0", + "next": "15.1.4", + "react": "19.0.0", + "react-dom": "19.0.0", "use-deep-compare-effect": "^1.8.1" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/spotlight/src/components/actions/children-actions.tsx b/packages/spotlight/src/components/actions/children-actions.tsx index b7f36909d..1907792a3 100644 --- a/packages/spotlight/src/components/actions/children-actions.tsx +++ b/packages/spotlight/src/components/actions/children-actions.tsx @@ -4,14 +4,25 @@ import { ChildrenActionItem } from "./items/children-action-item"; interface SpotlightChildrenActionsProps { childrenOptions: inferSearchInteractionOptions<"children">; query: string; + setChildrenOptions: (options: inferSearchInteractionOptions<"children">) => void; } -export const SpotlightChildrenActions = ({ childrenOptions, query }: SpotlightChildrenActionsProps) => { +export const SpotlightChildrenActions = ({ + childrenOptions, + query, + setChildrenOptions, +}: SpotlightChildrenActionsProps) => { const actions = childrenOptions.useActions(childrenOptions.option, query); return actions .filter((action) => (typeof action.hide === "function" ? !action.hide(childrenOptions.option) : !action.hide)) .map((action) => ( - + )); }; diff --git a/packages/spotlight/src/components/actions/items/children-action-item.tsx b/packages/spotlight/src/components/actions/items/children-action-item.tsx index 0b070b147..777446b78 100644 --- a/packages/spotlight/src/components/actions/items/children-action-item.tsx +++ b/packages/spotlight/src/components/actions/items/children-action-item.tsx @@ -8,9 +8,10 @@ interface ChildrenActionItemProps { childrenOptions: inferSearchInteractionOptions<"children">; query: string; action: ReturnType["useActions"]>[number]; + setChildrenOptions: (options: inferSearchInteractionOptions<"children">) => void; } -export const ChildrenActionItem = ({ childrenOptions, action, query }: ChildrenActionItemProps) => { +export const ChildrenActionItem = ({ childrenOptions, action, query, setChildrenOptions }: ChildrenActionItemProps) => { const interaction = action.useInteraction(childrenOptions.option, query); const renderRoot = @@ -20,10 +21,20 @@ export const ChildrenActionItem = ({ childrenOptions, action, query }: ChildrenA } : undefined; - const onClick = interaction.type === "javaScript" ? interaction.onSelect : undefined; + const onClick = + interaction.type === "javaScript" + ? interaction.onSelect + : interaction.type === "children" + ? () => setChildrenOptions(interaction) + : undefined; return ( - + ); diff --git a/packages/spotlight/src/components/actions/items/group-action-item.tsx b/packages/spotlight/src/components/actions/items/group-action-item.tsx index 6dd70c5ff..a4221f514 100644 --- a/packages/spotlight/src/components/actions/items/group-action-item.tsx +++ b/packages/spotlight/src/components/actions/items/group-action-item.tsx @@ -45,7 +45,9 @@ export const SpotlightGroupActionItem = diff --git a/packages/spotlight/src/components/spotlight.tsx b/packages/spotlight/src/components/spotlight.tsx index 1ab051bb7..1f4158076 100644 --- a/packages/spotlight/src/components/spotlight.tsx +++ b/packages/spotlight/src/components/spotlight.tsx @@ -1,10 +1,10 @@ "use client"; import type { Dispatch, SetStateAction } from "react"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useMemo, useRef, useState } from "react"; import { ActionIcon, Center, Group, Kbd } from "@mantine/core"; import { Spotlight as MantineSpotlight } from "@mantine/spotlight"; -import { IconSearch, IconX } from "@tabler/icons-react"; +import { IconQuestionMark, IconSearch, IconX } from "@tabler/icons-react"; import type { TranslationObject } from "@homarr/translation"; import { useI18n } from "@homarr/translation/client"; @@ -12,53 +12,32 @@ import { useI18n } from "@homarr/translation/client"; import type { inferSearchInteractionOptions } from "../lib/interaction"; import type { SearchMode } from "../lib/mode"; import { searchModes } from "../modes"; -import { useSpotlightContextResults } from "../modes/home/context"; import { selectAction, spotlightStore } from "../spotlight-store"; import { SpotlightChildrenActions } from "./actions/children-actions"; import { SpotlightActionGroups } from "./actions/groups/action-group"; type SearchModeKey = keyof TranslationObject["search"]["mode"]; +const defaultMode = "home"; export const Spotlight = () => { - const items = useSpotlightContextResults(); - // We fallback to help if no context results are available - const defaultMode = items.length >= 1 ? "home" : "help"; const searchModeState = useState(defaultMode); const mode = searchModeState[0]; const activeMode = useMemo(() => searchModes.find((searchMode) => searchMode.modeKey === mode), [mode]); - /** - * The below logic is used to switch to home page if any context results are registered - * or to help page if context results are unregistered - */ - const previousLengthRef = useRef(items.length); - useEffect(() => { - if (items.length >= 1 && previousLengthRef.current === 0) { - searchModeState[1]("home"); - } else if (items.length === 0 && previousLengthRef.current >= 1) { - searchModeState[1]("help"); - } - - previousLengthRef.current = items.length; - }, [items.length, searchModeState]); - if (!activeMode) { return null; } // We use the "key" below to prevent the 'Different amounts of hooks' error - return ( - - ); + return ; }; interface SpotlightWithActiveModeProps { modeState: [SearchModeKey, Dispatch>]; activeMode: SearchMode; - defaultMode: SearchModeKey; } -const SpotlightWithActiveMode = ({ modeState, activeMode, defaultMode }: SpotlightWithActiveModeProps) => { +const SpotlightWithActiveMode = ({ modeState, activeMode }: SpotlightWithActiveModeProps) => { const [query, setQuery] = useState(""); const [mode, setMode] = modeState; const [childrenOptions, setChildrenOptions] = useState | null>(null); @@ -77,7 +56,7 @@ const SpotlightWithActiveMode = ({ modeState, activeMode, defaultMode }: Spotlig }} query={query} onQueryChange={(query) => { - if ((mode !== "help" && mode !== "home") || query.length !== 1) { + if (mode !== "help" || query.length !== 1) { setQuery(query); } @@ -110,7 +89,17 @@ const SpotlightWithActiveMode = ({ modeState, activeMode, defaultMode }: Spotlig }, }} rightSection={ - mode === defaultMode ? undefined : ( + mode === defaultMode ? ( + { + setMode("help"); + inputRef.current?.focus(); + }} + variant="subtle" + > + + + ) : ( { setMode(defaultMode); @@ -140,7 +129,11 @@ const SpotlightWithActiveMode = ({ modeState, activeMode, defaultMode }: Spotlig {childrenOptions ? ( - + ) : ( { diff --git a/packages/spotlight/src/lib/children.ts b/packages/spotlight/src/lib/children.ts index 0c2c34992..f7f8bdf83 100644 --- a/packages/spotlight/src/lib/children.ts +++ b/packages/spotlight/src/lib/children.ts @@ -10,7 +10,10 @@ export interface CreateChildrenOptionsProps> { key: string; Component: (option: TParentOptions) => JSX.Element; - useInteraction: (option: TParentOptions, query: string) => inferSearchInteractionDefinition<"link" | "javaScript">; + useInteraction: ( + option: TParentOptions, + query: string, + ) => inferSearchInteractionDefinition<"link" | "javaScript" | "children">; hide?: boolean | ((option: TParentOptions) => boolean); } diff --git a/packages/spotlight/src/lib/group.ts b/packages/spotlight/src/lib/group.ts index 4049d1a8e..d68a1e05c 100644 --- a/packages/spotlight/src/lib/group.ts +++ b/packages/spotlight/src/lib/group.ts @@ -1,5 +1,4 @@ import type { JSX } from "react"; -import type { UseTRPCQueryResult } from "@trpc/react-query/shared"; import type { stringOrTranslation } from "@homarr/translation"; @@ -29,9 +28,12 @@ export type SearchGroup = any> = { filter: (query: string, option: TOption) => boolean; sort?: (query: string, options: [TOption, TOption]) => number; - useOptions: () => TOption[]; + useOptions: (query: string) => TOption[]; } > - | CommonSearchGroup UseTRPCQueryResult }>; + | CommonSearchGroup< + TOption, + { useQueryOptions: (query: string) => { data: TOption[] | undefined; isLoading: boolean; isError: boolean } } + >; export const createGroup = >(group: SearchGroup) => group; diff --git a/packages/spotlight/src/lib/interaction.ts b/packages/spotlight/src/lib/interaction.ts index b917b3bcd..1854c8c48 100644 --- a/packages/spotlight/src/lib/interaction.ts +++ b/packages/spotlight/src/lib/interaction.ts @@ -4,7 +4,7 @@ import type { TranslationObject } from "@homarr/translation"; import type { CreateChildrenOptionsProps } from "./children"; const createSearchInteraction = (type: TType) => ({ - optionsType: >() => ({ type, _inferOptions: {} as TOption }), + optionsType: | undefined>() => ({ type, _inferOptions: {} as TOption }), }); // This is used to define search interactions with their options @@ -20,20 +20,23 @@ const searchInteractions = [ // eslint-disable-next-line @typescript-eslint/no-explicit-any option: any; }>(), + createSearchInteraction("none").optionsType(), ] as const; // Union of all search interactions types export type SearchInteraction = (typeof searchInteractions)[number]["type"]; // Infer the options for the specified search interaction -export type inferSearchInteractionOptions = Extract< - (typeof searchInteractions)[number], - { type: TInteraction } ->["_inferOptions"]; +export type inferSearchInteractionOptions = Exclude< + Extract<(typeof searchInteractions)[number], { type: TInteraction }>["_inferOptions"], + undefined +>; // Infer the search interaction definition (type + options) for the specified search interaction export type inferSearchInteractionDefinition = { - [interactionKey in TInteraction]: { type: interactionKey } & inferSearchInteractionOptions; + [interactionKey in TInteraction]: inferSearchInteractionOptions extends never + ? { type: interactionKey } + : { type: interactionKey } & inferSearchInteractionOptions; }[TInteraction]; // Type used for helper functions to define basic search interactions diff --git a/packages/spotlight/src/modes/app-integration-board/boards-search-group.tsx b/packages/spotlight/src/modes/app-integration-board/boards-search-group.tsx index ca201b5bc..e093795f1 100644 --- a/packages/spotlight/src/modes/app-integration-board/boards-search-group.tsx +++ b/packages/spotlight/src/modes/app-integration-board/boards-search-group.tsx @@ -1,5 +1,5 @@ import { Group, Stack, Text } from "@mantine/core"; -import { IconHome, IconLayoutDashboard, IconLink, IconSettings } from "@tabler/icons-react"; +import { IconDeviceMobile, IconHome, IconLayoutDashboard, IconLink, IconSettings } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { useI18n } from "@homarr/translation/client"; @@ -59,6 +59,30 @@ const boardChildrenOptions = createChildrenOptions({ }; }, }, + { + key: "mobileBoard", + Component: () => { + const t = useI18n(); + + return ( + + + {t("search.mode.appIntegrationBoard.group.board.children.action.mobileBoard.label")} + + ); + }, + useInteraction(option) { + const { mutateAsync } = clientApi.board.setMobileHomeBoard.useMutation(); + + return { + type: "javaScript", + // eslint-disable-next-line no-restricted-syntax + async onSelect() { + await mutateAsync({ id: option.id }); + }, + }; + }, + }, { key: "settings", Component: () => { diff --git a/packages/spotlight/src/modes/external/search-engines-search-group.tsx b/packages/spotlight/src/modes/external/search-engines-search-group.tsx index 5c6529624..57bde8cb6 100644 --- a/packages/spotlight/src/modes/external/search-engines-search-group.tsx +++ b/packages/spotlight/src/modes/external/search-engines-search-group.tsx @@ -1,15 +1,161 @@ import { Group, Image, Kbd, Stack, Text } from "@mantine/core"; -import { IconSearch } from "@tabler/icons-react"; +import { IconDownload, IconSearch } from "@tabler/icons-react"; import type { RouterOutputs } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; +import type { IntegrationKind } from "@homarr/definitions"; +import { getIntegrationKindsByCategory, getIntegrationName } from "@homarr/definitions"; +import { useModalAction } from "@homarr/modals"; +import { RequestMediaModal } from "@homarr/modals-collection"; import { useScopedI18n } from "@homarr/translation/client"; import { createChildrenOptions } from "../../lib/children"; import { createGroup } from "../../lib/group"; +import type { inferSearchInteractionDefinition } from "../../lib/interaction"; import { interaction } from "../../lib/interaction"; type SearchEngine = RouterOutputs["searchEngine"]["search"][number]; +type FromIntegrationSearchResult = RouterOutputs["integration"]["searchInIntegration"][number]; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +type MediaRequestChildrenProps = { + result: { + id: number; + image?: string; + name: string; + link: string; + text?: string; + type: "tv" | "movie"; + inLibrary: boolean; + }; + integration: { + kind: IntegrationKind; + url: string; + id: string; + }; +}; + +export const useFromIntegrationSearchInteraction = ( + searchEngine: SearchEngine, + searchResult: FromIntegrationSearchResult, +): inferSearchInteractionDefinition<"link" | "javaScript" | "children"> => { + if (searchEngine.type !== "fromIntegration") { + throw new Error("Invalid search engine type"); + } + + if (!searchEngine.integration) { + throw new Error("Invalid search engine integration"); + } + + if ( + getIntegrationKindsByCategory("mediaRequest").some( + (categoryKind) => categoryKind === searchEngine.integration?.kind, + ) && + "type" in searchResult + ) { + const type = searchResult.type; + if (type === "person") { + return { + type: "link", + href: searchResult.link, + newTab: true, + }; + } + + return { + type: "children", + ...mediaRequestsChildrenOptions({ + result: { + ...searchResult, + type, + }, + integration: searchEngine.integration, + }), + }; + } + + return { + type: "link", + href: searchResult.link, + newTab: true, + }; +}; + +const mediaRequestsChildrenOptions = createChildrenOptions({ + useActions() { + const { openModal } = useModalAction(RequestMediaModal); + return [ + { + key: "request", + hide: (option) => option.result.inLibrary, + Component(option) { + const t = useScopedI18n("search.mode.media"); + return ( + + + {option.result.type === "tv" && {t("requestSeries")}} + {option.result.type === "movie" && {t("requestMovie")}} + + ); + }, + useInteraction: interaction.javaScript((option) => ({ + onSelect() { + openModal( + { + integrationId: option.integration.id, + mediaId: option.result.id, + mediaType: option.result.type, + }, + { + title(t) { + return t("search.engine.media.request.modal.title", { name: option.result.name }); + }, + }, + ); + }, + })), + }, + { + key: "open", + Component({ integration }) { + const tChildren = useScopedI18n("search.mode.media"); + return ( + + + {tChildren("openIn", { kind: getIntegrationName(integration.kind) })} + + ); + }, + useInteraction({ result }) { + return { + type: "link", + href: result.link, + newTab: true, + }; + }, + }, + ]; + }, + DetailComponent({ options }) { + return ( + + {options.result.image ? ( + + ) : ( + + )} + + {options.result.name} + {options.result.text && ( + + {options.result.text} + + )} + + + ); + }, +}); export const searchEnginesChildrenOptions = createChildrenOptions({ useActions: (searchEngine, query) => { @@ -64,10 +210,9 @@ export const searchEnginesChildrenOptions = createChildrenOptions( ); }, - useInteraction: interaction.link(() => ({ - href: searchResult.link, - newTab: true, - })), + useInteraction() { + return useFromIntegrationSearchInteraction(searchEngine, searchResult); + }, })); }, DetailComponent({ options }) { diff --git a/packages/spotlight/src/modes/home/home-search-engine-group.tsx b/packages/spotlight/src/modes/home/home-search-engine-group.tsx new file mode 100644 index 000000000..d99cb3713 --- /dev/null +++ b/packages/spotlight/src/modes/home/home-search-engine-group.tsx @@ -0,0 +1,173 @@ +import { Box, Group, Stack, Text } from "@mantine/core"; +import type { TablerIcon } from "@tabler/icons-react"; +import { IconCaretUpDown, IconSearch, IconSearchOff } from "@tabler/icons-react"; + +import type { RouterOutputs } from "@homarr/api"; +import { clientApi } from "@homarr/api/client"; +import type { Session } from "@homarr/auth"; +import { useSession } from "@homarr/auth/client"; +import type { TranslationFunction } from "@homarr/translation"; +import { useI18n } from "@homarr/translation/client"; + +import { createGroup } from "../../lib/group"; +import type { inferSearchInteractionDefinition, SearchInteraction } from "../../lib/interaction"; +import { useFromIntegrationSearchInteraction } from "../external/search-engines-search-group"; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +type GroupItem = { + id: string; + name: string; + description?: string; + icon: TablerIcon | string; + useInteraction: (query: string) => inferSearchInteractionDefinition; +}; + +export const homeSearchEngineGroup = createGroup({ + title: (t) => t("search.mode.home.group.search.title"), + keyPath: "id", + Component(item) { + const icon = + typeof item.icon !== "string" ? ( + + ) : ( + + {item.name} + + ); + + return ( + + {icon} + + {item.name} + {item.description && ( + + {item.description} + + )} + + + ); + }, + useInteraction(item, query) { + return item.useInteraction(query); + }, + filter() { + return true; + }, + useQueryOptions(query) { + const t = useI18n(); + const { data: session, status } = useSession(); + const { data: defaultSearchEngine, ...defaultSearchEngineQuery } = + clientApi.searchEngine.getDefaultSearchEngine.useQuery(undefined, { + enabled: status !== "loading", + }); + const fromIntegrationEnabled = defaultSearchEngine?.type === "fromIntegration" && query.length > 0; + const { data: results, ...resultQuery } = clientApi.integration.searchInIntegration.useQuery( + { + query, + integrationId: defaultSearchEngine?.integrationId ?? "", + }, + { + enabled: fromIntegrationEnabled, + select: (data) => data.slice(0, 5), + }, + ); + + return { + isLoading: + defaultSearchEngineQuery.isLoading || (resultQuery.isLoading && fromIntegrationEnabled) || status === "loading", + isError: defaultSearchEngineQuery.isError || (resultQuery.isError && fromIntegrationEnabled), + data: [ + ...createDefaultSearchEntries(defaultSearchEngine, results, session, query, t), + { + id: "other", + name: t("search.mode.home.group.search.option.other.label"), + icon: IconCaretUpDown, + useInteraction() { + return { + type: "mode", + mode: "external", + }; + }, + }, + ], + }; + }, +}); + +const createDefaultSearchEntries = ( + defaultSearchEngine: RouterOutputs["searchEngine"]["getDefaultSearchEngine"] | null, + results: RouterOutputs["integration"]["searchInIntegration"] | undefined, + session: Session | null, + query: string, + t: TranslationFunction, +): GroupItem[] => { + if (!session?.user && !defaultSearchEngine) { + return []; + } + + if (!defaultSearchEngine) { + return [ + { + id: "no-default", + name: t("search.mode.home.group.search.option.no-default.label"), + description: t("search.mode.home.group.search.option.no-default.description"), + icon: IconSearchOff, + useInteraction() { + return { + type: "link", + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + href: `/manage/users/${session!.user.id}/general`, + }; + }, + }, + ]; + } + + if (defaultSearchEngine.type === "generic") { + return [ + { + id: "search", + name: t("search.mode.home.group.search.option.search.label", { + query, + name: defaultSearchEngine.name, + }), + icon: defaultSearchEngine.iconUrl, + useInteraction(query) { + return { + type: "link", + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + href: defaultSearchEngine.urlTemplate!.replace("%s", query), + }; + }, + }, + ]; + } + + if (!results) { + return [ + { + id: "from-integration", + name: defaultSearchEngine.name, + icon: defaultSearchEngine.iconUrl, + description: t("search.mode.home.group.search.option.from-integration.description"), + useInteraction() { + return { + type: "none", + }; + }, + }, + ]; + } + + return results.map((result) => ({ + id: `search-${result.id}`, + name: result.name, + description: result.text, + icon: result.image ?? IconSearch, + useInteraction() { + return useFromIntegrationSearchInteraction(defaultSearchEngine, result); + }, + })); +}; diff --git a/packages/spotlight/src/modes/home/index.tsx b/packages/spotlight/src/modes/home/index.tsx index e306437f2..7851e6a39 100644 --- a/packages/spotlight/src/modes/home/index.tsx +++ b/packages/spotlight/src/modes/home/index.tsx @@ -1,8 +1,9 @@ import type { SearchMode } from "../../lib/mode"; import { contextSpecificSearchGroups } from "./context-specific-group"; +import { homeSearchEngineGroup } from "./home-search-engine-group"; export const homeMode = { character: undefined, modeKey: "home", - groups: [contextSpecificSearchGroups], + groups: [homeSearchEngineGroup, contextSpecificSearchGroups], } satisfies SearchMode; diff --git a/packages/translation/package.json b/packages/translation/package.json index f2540fbd9..d6361d77b 100644 --- a/packages/translation/package.json +++ b/packages/translation/package.json @@ -31,16 +31,17 @@ "@homarr/definitions": "workspace:^0.1.0", "dayjs": "^1.11.13", "deepmerge": "4.3.1", - "mantine-react-table": "2.0.0-beta.7", - "next": "^14.2.20", - "next-intl": "3.26.1", - "react": "^19.0.0" + "mantine-react-table": "2.0.0-beta.8", + "next": "15.1.4", + "next-intl": "3.26.3", + "react": "19.0.0", + "react-dom": "19.0.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/translation/src/lang/cn.json b/packages/translation/src/lang/cn.json index e7cd1a4d2..3d3af4bde 100644 --- a/packages/translation/src/lang/cn.json +++ b/packages/translation/src/lang/cn.json @@ -1,10 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "欢迎使用 Homarr", + "subtitle": "让我们开始设置您的 Homarr 实例。", + "description": "首先,请选择您想要如何设置您的 Homarr 实例。", + "action": { + "scratch": "从零开始", + "importOldmarr": "从 1.0 之前的 Homarr 导入" + } + }, + "import": { + "title": "导入数据", + "subtitle": "您可以从已有的 Homarr 实例导入数据。", + "dropzone": { + "title": "将 zip 文件拖到此处或单击浏览", + "description": "上传的压缩包将被处理,您可以选择要导入的内容" + }, + "fileInfo": { + "action": { + "change": "更改文件" + } + }, + "importSettings": { + "title": "导入设置", + "description": "配置导入方式" + }, + "boardSelection": { + "title": "找到 {count} 个面板", + "description": "选择您想要导入的所有面板", + "action": { + "selectAll": "选择全部", + "unselectAll": "取消全选" + } + }, + "summary": { + "title": "导入概况", + "description": "在下面的概况中,您可以看到将要导入的内容", + "action": { + "import": "确认导入并继续" + }, + "entities": { + "apps": "应用", + "boards": "面板", + "integrations": "集成", + "credentialUsers": "用户凭证" + } + }, + "tokenModal": { + "title": "输入导入密钥", + "field": { + "token": { + "label": "秘钥", + "description": "输入您之前的 homarr 实例中显示的导入秘钥" + } + }, + "notification": { + "error": { + "title": "无效秘钥", + "message": "您输入的秘钥无效" + } + } + } + }, + "user": { + "title": "管理员用户", + "subtitle": "指定您的管理员用户的凭证。", + "notification": { + "success": { + "title": "创建用户", + "message": "用户已成功创建" + }, + "error": { + "title": "用户创建失败" + } + } + }, + "group": { + "title": "外部用户组", + "subtitle": "指定应该用于外部用户的用户组。", + "form": { + "name": { + "label": "用户组名称", + "description": "名称必须与外部提供商的管理组匹配" + } + } + }, + "settings": { + "title": "设置", + "subtitle": "配置服务器的设置" + }, + "finish": { + "title": "完成设置", + "subtitle": "你已设置完成!", + "description": "您已成功完成设置过程。现在您可以开始使用 Homarr 了。选择下一步操作:", + "action": { + "goToBoard": "转到 {name} 面板", + "createBoard": "创建您的第一个面板", + "inviteUser": "邀请其他用户", + "docs": "阅读文档" + } + } + }, + "backToStart": "返回起点" + }, "user": { "title": "用户", "name": "用户", + "page": { + "login": { + "title": "登录你的账户", + "subtitle": "欢迎回来!请输入您的凭证" + }, + "invite": { + "title": "加入 Homarr", + "subtitle": "欢迎来到 Homarr!请创建您的账户", + "description": "您受到了 {username} 的邀请。" + }, + "init": { + "title": "新建 Homarr 安装", + "subtitle": "请创建初始管理员用户" + } + }, "field": { "email": { - "label": "邮箱" + "label": "邮箱", + "verified": "已验证" }, "username": { "label": "用户名" @@ -12,117 +133,747 @@ "password": { "label": "密码", "requirement": { - "lowercase": "包括小写字母", + "length": "至少包含 8 个字符", + "lowercase": "包含小写字母", "uppercase": "包含大写字母", - "number": "包含数字" + "number": "包含数字", + "special": "包含特殊符号" } }, "passwordConfirm": { "label": "确认密码" + }, + "previousPassword": { + "label": "以前的密码" + }, + "homeBoard": { + "label": "主面板" + }, + "pingIconsEnabled": { + "label": "为 ping 使用图标" } }, + "error": { + "usernameTaken": "用户名已存在" + }, "action": { "login": { - "label": "登录" + "label": "登录", + "labelWith": "使用 {provider} 登录", + "notification": { + "success": { + "title": "登录成功", + "message": "您已登录" + }, + "error": { + "title": "登录失败", + "message": "您的登录失败了" + } + }, + "forgotPassword": { + "label": "忘记了你的密码?", + "description": "管理员可以使用以下命令重置密码:" + } }, "register": { "label": "创建账号", "notification": { "success": { - "title": "账号已创建" + "title": "账号已创建", + "message": "请登录后继续" + }, + "error": { + "title": "账户创建失败", + "message": "无法创建您的账户" } } }, - "create": "创建用户" + "create": "创建用户", + "changePassword": { + "label": "修改密码", + "notification": { + "success": { + "message": "密码修改成功" + }, + "error": { + "message": "无法修改密码" + } + } + }, + "changeHomeBoard": { + "notification": { + "success": { + "message": "主面板修改成功" + }, + "error": { + "message": "无法修改主面板" + } + } + }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "默认搜索引擎更改成功" + }, + "error": { + "message": "无法更改默认的搜索引擎" + } + } + }, + "changeFirstDayOfWeek": { + "notification": { + "success": { + "message": "成功修改一周的第一天" + }, + "error": { + "message": "无法修改一周的第一天" + } + } + }, + "changePingIconsEnabled": { + "notification": { + "success": { + "message": "Ping 图标切换成功" + }, + "error": { + "message": "无法切换 ping 图标" + } + } + }, + "manageAvatar": { + "changeImage": { + "label": "更改头像", + "notification": { + "success": { + "message": "头像修改成功" + }, + "error": { + "message": "无法更改图像" + }, + "toLarge": { + "title": "图片太大", + "message": "最大图像尺寸为 {size}" + } + } + }, + "removeImage": { + "label": "删除图像", + "confirm": "确定要移除这张图片吗?", + "notification": { + "success": { + "message": "图像删除成功" + }, + "error": { + "message": "无法删除图像" + } + } + } + }, + "editProfile": { + "notification": { + "success": { + "message": "资料更新成功" + }, + "error": { + "message": "资料更新失败" + } + } + }, + "delete": { + "label": "永久删除用户", + "description": "删除此用户(包括其偏好设置)。这不会删除任何面板。用户不会收到通知。", + "confirm": "您确定要删除用户 {username} 及其偏好设置吗?" + }, + "select": { + "label": "选择用户", + "notFound": "找不到用户" + }, + "transfer": { + "label": "选择新的所有者" + } } }, "group": { + "title": "群组", + "name": "组", + "search": "查找群组", "field": { - "name": "名称" + "name": "名称", + "members": "成员" }, "permission": { "admin": { - "title": "管理员" + "title": "管理员", + "item": { + "admin": { + "label": "管理员", + "description": "拥有此权限的成员可完全访问所有功能和设置" + } + } + }, + "app": { + "title": "应用", + "item": { + "create": { + "label": "创建应用", + "description": "允许成员创建应用" + }, + "use-all": { + "label": "使用全部应用", + "description": "允许成员将任意应用添加到他们的面板" + }, + "modify-all": { + "label": "修改所有应用", + "description": "允许成员修改全部应用" + }, + "full-all": { + "label": "完整应用访问权限", + "description": "允许成员管理、使用和删除任意应用" + } + } }, "board": { - "title": "面板" + "title": "面板", + "item": { + "create": { + "label": "创建面板", + "description": "允许成员创建面板" + }, + "view-all": { + "label": "查看全部面板", + "description": "允许成员查看全部面板" + }, + "modify-all": { + "label": "修改全部面板", + "description": "允许成员修改全部面板 (不包括访问控制和危险区域)" + }, + "full-all": { + "label": "完整的面板访问权限", + "description": "允许成员查看、修改和删除全部面板 (包括访问控制和危险区域)" + } + } + }, + "integration": { + "title": "集成", + "item": { + "create": { + "label": "创建集成", + "description": "允许成员创建集成" + }, + "use-all": { + "label": "使用全部集成", + "description": "允许成员将任意集成添加到他们的面板" + }, + "interact-all": { + "label": "与任意集成进行互动", + "description": "允许成员与任意集成进行交互" + }, + "full-all": { + "label": "完整的集成访问权限", + "description": "允许成员管理、使用并与任意集成交互" + } + } + }, + "media": { + "title": "媒体", + "item": { + "upload": { + "label": "上传媒体", + "description": "允许成员上传媒体" + }, + "view-all": { + "label": "查看全部媒体", + "description": "允许成员查看全部媒体" + }, + "full-all": { + "label": "完全的媒体访问权限", + "description": "允许成员管理和删除任意媒体" + } + } + }, + "other": { + "title": "其它", + "item": { + "view-logs": { + "label": "查看日志", + "description": "允许成员查看日志" + } + } + }, + "search-engine": { + "title": "搜索引擎", + "item": { + "create": { + "label": "创建搜索引擎", + "description": "允许成员创建搜索引擎" + }, + "modify-all": { + "label": "修改全部搜索引擎", + "description": "允许成员修改全部搜索引擎" + }, + "full-all": { + "label": "完整的搜索引擎访问权限", + "description": "允许成员管理和删除任何搜索引擎" + } + } + } + }, + "memberNotice": { + "mixed": "部分成员来自外部提供者,无法在此处管理", + "external": "所有成员都来自外部提供者,无法在此处管理" + }, + "reservedNotice": { + "message": "此用户组保留供系统使用并限制部分操作 " + }, + "action": { + "create": { + "label": "新建群组", + "notification": { + "success": { + "message": "群组已成功创建" + }, + "error": { + "message": "无法创建群组" + } + } + }, + "transfer": { + "label": "转移所有权", + "description": "将此用户组的所有权转移给另一个用户。", + "confirm": "确定将用户组 {name} 的所有权转移给 {username} 吗?", + "notification": { + "success": { + "message": "成功将用户组 {group} 的所有权转移给 {user}" + }, + "error": { + "message": "无法转移所有权" + } + } + }, + "addMember": { + "label": "添加成员" + }, + "removeMember": { + "label": "删除成员", + "confirm": "确定将 {user} 从此用户组移除吗?" + }, + "delete": { + "label": "删除用户组", + "description": "用户组一旦删除就无法恢复. 请谨慎操作.", + "confirm": "确认删除用户组 {name} 吗?", + "notification": { + "success": { + "message": "成功删除用户组 {name}" + }, + "error": { + "message": "无法删除用户组 {name}" + } + } + }, + "changePermissions": { + "notification": { + "success": { + "title": "权限已保存", + "message": "权限保存成功" + }, + "error": { + "title": "权限未保存", + "message": "权限尚未保存" + } + } + }, + "update": { + "notification": { + "success": { + "message": "用户组 {name} 保存成功" + }, + "error": { + "message": "无法保存用户组 {name}" + } + } + }, + "select": { + "label": "选择用户组", + "notFound": "未找到用户组" } } }, "app": { + "search": "查找应用", "page": { "list": { - "title": "应用" + "title": "应用", + "noResults": { + "title": "尚无应用", + "action": "创建您的第一个应用" + } + }, + "create": { + "title": "新建应用", + "notification": { + "success": { + "title": "创建成功", + "message": "应用已成功创建" + }, + "error": { + "title": "创建失败", + "message": "无法创建应用" + } + } + }, + "edit": { + "title": "编辑应用", + "notification": { + "success": { + "title": "成功应用更改", + "message": "应用保存成功" + }, + "error": { + "title": "无法应用更改", + "message": "应用无法保存" + } + } + }, + "delete": { + "title": "删除应用", + "message": "确认删除应用 {name} 吗?", + "notification": { + "success": { + "title": "删除成功", + "message": "应用已成功删除" + }, + "error": { + "title": "删除失败", + "message": "无法删除应用" + } + } } }, "field": { "name": { "label": "名称" + }, + "description": { + "label": "描述" + }, + "url": { + "label": "Url" + } + }, + "action": { + "select": { + "label": "选择应用", + "notFound": "未找到应用" } } }, "integration": { + "page": { + "list": { + "title": "集成", + "search": "搜索集成", + "noResults": { + "title": "尚无集成" + } + }, + "create": { + "title": "新的集成 {name}", + "notification": { + "success": { + "title": "创建成功", + "message": "组件已成功创建" + }, + "error": { + "title": "创建失败", + "message": "无法创建组件" + } + } + }, + "edit": { + "title": "编辑集成 {name}", + "notification": { + "success": { + "title": "成功应用更改", + "message": "集成已成功保存" + }, + "error": { + "title": "无法应用更改", + "message": "无法保存此集成" + } + } + }, + "delete": { + "title": "删除集成", + "message": "确认删除集成 {name} 吗?", + "notification": { + "success": { + "title": "删除成功", + "message": "集成已成功删除" + }, + "error": { + "title": "删除失败", + "message": "无法删除集成" + } + } + } + }, "field": { "name": { "label": "名称" + }, + "url": { + "label": "Url" + }, + "attemptSearchEngineCreation": { + "label": "创建搜索引擎", + "description": "集成“{kind}”可以与搜索引擎一起使用。勾选此项可自动配置搜索引擎。" } }, + "action": { + "create": "新建集成" + }, "testConnection": { + "action": { + "create": "测试连接并创建", + "edit": "测试连接并保存" + }, + "alertNotice": "成功建立连接后保存按钮将启用", "notification": { + "success": { + "title": "连接成功", + "message": "已成功建立连接" + }, "invalidUrl": { - "title": "无效链接" + "title": "无效链接", + "message": "URL 无效" + }, + "secretNotDefined": { + "title": "缺少凭证", + "message": "并非所有凭证都已提供" + }, + "invalidCredentials": { + "title": "凭证无效", + "message": "凭证无效" + }, + "commonError": { + "title": "连接失败", + "message": "无法建立连接" + }, + "badRequest": { + "title": "错误请求", + "message": "请求格式不正确" + }, + "unauthorized": { + "title": "未授权", + "message": "可能错误的凭证" + }, + "forbidden": { + "title": "禁止", + "message": "可能缺少权限" + }, + "notFound": { + "title": "未找到", + "message": "可能错误的 URL 或路径" + }, + "internalServerError": { + "title": "服务器内部错误", + "message": "服务器遇到一个错误" + }, + "serviceUnavailable": { + "title": "服务暂时不可用", + "message": "服务器当前不可用" + }, + "connectionAborted": { + "title": "连接被中止", + "message": "连接被终止" + }, + "domainNotFound": { + "title": "找不到域", + "message": "找不到该域" + }, + "connectionRefused": { + "title": "连接被拒绝", + "message": "连接被拒绝" + }, + "invalidJson": { + "title": "无效的 JSON", + "message": "无效的JSON响应" + }, + "wrongPath": { + "title": "路径错误", + "message": "该路径可能不正确" } } }, "secrets": { + "title": "秘钥", + "lastUpdated": "最后更新于 {date}", + "notSet": { + "label": "未设置值", + "tooltip": "尚未设置此必填的密钥" + }, + "secureNotice": "创建后无法再次获取此密钥", + "reset": { + "title": "重置密钥", + "message": "您确定要重置此秘钥吗?" + }, + "noSecretsRequired": { + "segmentTitle": "没有密钥", + "text": "此集成不需要密钥" + }, "kind": { "username": { - "label": "用户名" + "label": "用户名", + "newLabel": "新用户名" + }, + "apiKey": { + "label": "API 密钥", + "newLabel": "新 API 密钥" }, "password": { "label": "密码", "newLabel": "新密码" } } + }, + "permission": { + "use": "选择项目中的集成", + "interact": "与集成进行互动", + "full": "完整的组件访问权限" } }, "media": { + "plural": "媒体", + "search": "查找媒体", "field": { "name": "名称", "size": "大小", "creator": "创建者" + }, + "action": { + "upload": { + "label": "上传媒体", + "file": "选择文件", + "notification": { + "success": { + "message": "上传媒体成功" + }, + "error": { + "message": "无法上传媒体" + } + } + }, + "delete": { + "label": "删除媒体", + "description": "您确定要删除媒体 ?", + "notification": { + "success": { + "message": "媒体已成功删除" + }, + "error": { + "message": "无法删除该媒体" + } + } + }, + "copy": { + "label": "复制 URL" + } } }, "common": { + "beta": "测试版", "error": "错误", "action": { "add": "添加", "apply": "应用", + "backToOverview": "返回概览", "create": "创建", "edit": "编辑", + "import": "导入", "insert": "插入", "remove": "删除", "save": "保存", "saveChanges": "保存更改", "cancel": "取消", "delete": "删除", + "discard": "Discard", "confirm": "确认", + "continue": "继续", "previous": "上一步", "next": "下一步", - "tryAgain": "请再试一次" + "checkoutDocs": "查阅文档", + "checkLogs": "检查日志获取更多详情", + "tryAgain": "重试", + "loading": "正在加载" + }, + "here": "这里", + "iconPicker": { + "label": "图标 URL", + "header": "输入名称或对象来筛选图标… Homarr 将为您搜索 {countIcons} 图标。" + }, + "colorScheme": { + "options": { + "light": "日间", + "dark": "暗黑" + } }, "information": { + "min": "最小", + "max": "最大", + "days": "天", "hours": "时", "minutes": "分" }, + "notification": { + "create": { + "success": "创建成功", + "error": "创建失败" + }, + "delete": { + "success": "删除成功", + "error": "删除失败" + }, + "update": { + "success": "成功应用更改", + "error": "无法应用更改" + }, + "transfer": { + "success": "传输成功", + "error": "传输失败" + } + }, + "multiSelect": { + "placeholder": "选择一个或多个值" + }, + "multiText": { + "placeholder": "添加更多值", + "addLabel": "添加 {value}" + }, + "select": { + "placeholder": "选择值", + "badge": { + "recommended": "推荐" + } + }, "userAvatar": { "menu": { - "preferences": "您的首选项", - "login": "登录" + "switchToDarkMode": "切换到暗黑模式", + "switchToLightMode": "切换到日间模式", + "management": "管理中心", + "preferences": "偏好设置", + "logout": "退出登录", + "login": "登录", + "homeBoard": "您的首页", + "loggedOut": "已注销", + "updateAvailable": "{countUpdates} 可用更新:{tag}" } }, "dangerZone": "危险", "noResults": "未找到结果", + "preview": { + "show": "显示预览", + "hide": "隐藏预览" + }, "zod": { "errors": { "default": "该字段无效", @@ -130,20 +881,41 @@ "string": { "startsWith": "该字段必须以 {startsWith} 开头", "endsWith": "该字段必须以 {endsWith} 结尾", - "includes": "该字段必须包含 {includes}" + "includes": "该字段必须包含 {includes}", + "invalidEmail": "此字段必须是一个有效的电子邮件" }, "tooSmall": { - "string": "该字段的长度必须至少为 {minimum} 个字符", + "string": "该字段长度必须至少为 {minimum} 个字符", "number": "该字段必须大于或等于 {minimum}" }, "tooBig": { "string": "该字段的长度不得超过 {maximum} 个字符", "number": "该字段必须小于或等于 {maximum}" + }, + "custom": { + "passwordsDoNotMatch": "两次输入的密码不一致", + "passwordRequirements": "密码不符合要求", + "boardAlreadyExists": "具有此名称的面板已存在", + "invalidFileType": "无效的文件类型,例如 {expected}", + "invalidFileName": "", + "fileTooLarge": "文件太大,最大大小为 {maxSize}", + "invalidConfiguration": "无效配置", + "groupNameTaken": "用户组名称已存在" } } } }, "section": { + "dynamic": { + "action": { + "create": "新建动态部分", + "remove": "删除动态部分" + }, + "remove": { + "title": "删除动态部分", + "message": "你确定你要删除这个动态部分?项目将被移动到父节的相同位置。" + } + }, "category": { "field": { "name": { @@ -151,42 +923,148 @@ } }, "action": { + "create": "新建分类", + "edit": "重命名分类", + "remove": "删除分类", "moveUp": "上移", - "moveDown": "下移" + "moveDown": "下移", + "createAbove": "上方新建分类", + "createBelow": "下方新建分类" + }, + "create": { + "title": "新建分类", + "submit": "添加分类" + }, + "remove": { + "title": "删除分类", + "message": "您确定要删除分类 {name} 吗?" + }, + "edit": { + "title": "重命名分类", + "submit": "重命名分类" }, "menu": { "label": { + "create": "新建分类", "changePosition": "换位" } } } }, "item": { + "action": { + "create": "新建项目", + "import": "导入项目", + "edit": "编辑项目", + "moveResize": "移动/调整项目大小", + "duplicate": "复制项目", + "remove": "删除项目" + }, "menu": { "label": { "settings": "设置" } }, + "create": { + "title": "选择要添加的项目", + "search": "筛选项目", + "addToBoard": "添加到面板" + }, "moveResize": { + "title": "移动/调整项目大小", "field": { "width": { "label": "宽度" }, "height": { "label": "高度" + }, + "xOffset": { + "label": "X 偏移" + }, + "yOffset": { + "label": "Y 偏移" } } + }, + "edit": { + "title": "编辑项目", + "advancedOptions": { + "label": "高级选项", + "title": "高级项目选项" + }, + "field": { + "integrations": { + "label": "集成" + }, + "customCssClasses": { + "label": "自定义 CSS 类" + } + } + }, + "remove": { + "title": "删除项目", + "message": "你确定要删除这个项目吗?" } }, "widget": { "app": { + "name": "应用", + "description": "将应用嵌入到面板中。", "option": { + "appId": { + "label": "选择应用" + }, "openInNewTab": { "label": "在新标签页中打开" + }, + "showTitle": { + "label": "显示应用名称" + }, + "showDescriptionTooltip": { + "label": "显示描述提示" + }, + "pingEnabled": { + "label": "启用简单的 ping" + } + }, + "error": { + "notFound": { + "label": "没有应用", + "tooltip": "您没有选择有效的应用" + } + } + }, + "bookmarks": { + "name": "书签", + "description": "显示多个应用链接", + "option": { + "title": { + "label": "标题" + }, + "layout": { + "label": "显示布局", + "option": { + "row": { + "label": "横向" + }, + "column": { + "label": "垂直" + }, + "grid": { + "label": "网格" + } + } + }, + "items": { + "label": "书签", + "add": "添加书签" } } }, "dnsHoleSummary": { + "name": "DNS Hole 摘要", + "description": "显示 DNS Hole 的摘要", "option": { "layout": { "label": "显示布局", @@ -196,17 +1074,30 @@ }, "column": { "label": "垂直" + }, + "grid": { + "label": "网格" } } + }, + "usePiHoleColors": { + "label": "使用 Pi-Hole 颜色" } }, + "error": { + "internalServerError": "获取 DNS Hole 摘要失败", + "integrationsDisconnected": "没有可用的数据,所有集成已断开" + }, "data": { "adsBlockedToday": "今日屏蔽", "adsBlockedTodayPercentage": "今日屏蔽", - "dnsQueriesToday": "今日查询" - } + "dnsQueriesToday": "今日查询", + "domainsBeingBlocked": "黑名单上的域" + }, + "domainsTooltip": "由于多个集成,Homarr 无法计算被阻止的域的准确数量" }, "dnsHoleControls": { + "name": "DNS Hole 控制", "description": "从您的面板控制 PiHole 或 AdGuard", "option": { "layout": { @@ -217,28 +1108,89 @@ }, "column": { "label": "垂直" + }, + "grid": { + "label": "网格" } } + }, + "showToggleAllButtons": { + "label": "显示全部按钮" } }, + "error": { + "internalServerError": "无法控制 DNS Hole" + }, "controls": { + "enableAll": "全部启用", + "disableAll": "全部禁用", + "setTimer": "设置计时", "set": "设置", "enabled": "已启用", "disabled": "已禁用", + "processing": "处理中", + "disconnected": "网络连线中断", "hours": "时", - "minutes": "分" + "minutes": "分", + "unlimited": "留空表示无限制" } }, "clock": { + "name": "日期和时间", "description": "显示当前的日期和时间。", "option": { + "customTitleToggle": { + "label": "自定义标题/城市显示", + "description": "在时钟上显示自定义的标题或城市/国家的名称。" + }, + "customTitle": { + "label": "标题" + }, + "is24HourFormat": { + "label": "24 小时制", + "description": "使用24小时格式代替12小时格式" + }, + "showSeconds": { + "label": "显示秒数" + }, + "useCustomTimezone": { + "label": "使用固定时区" + }, "timezone": { - "label": "时区" + "label": "时区", + "description": "选择遵循 IANA 标准的时区" + }, + "showDate": { + "label": "显示日期" + }, + "dateFormat": { + "label": "日期格式", + "description": "日期应该是什么样的" } } }, + "minecraftServerStatus": { + "name": "Minecraft 服务状态", + "description": "显示 Minecraft 服务器状态", + "option": { + "title": { + "label": "标题" + }, + "domain": { + "label": "服务器地址" + }, + "isBedrockServer": { + "label": "Bedrock 服务器" + } + }, + "status": { + "online": "在线", + "offline": "离线" + } + }, "notebook": { - "name": "笔记本", + "name": "笔记", + "description": "支持 Markdown 的简单笔记本小部件", "option": { "showToolbar": { "label": "显示帮助您写下 Markdown 的工具栏" @@ -247,7 +1199,7 @@ "label": "允许在只读模式中检查" }, "content": { - "label": "笔记本的内容" + "label": "笔记的内容" } }, "controls": { @@ -256,7 +1208,7 @@ "strikethrough": "删除线", "underline": "下划线", "colorText": "文字颜色", - "colorHighlight": "彩色高亮文本", + "colorHighlight": "彩色高亮文字", "code": "代码", "clear": "清除格式", "heading": "标题 {level}", @@ -330,17 +1282,32 @@ } }, "error": { + "noUrl": "没有提供 iFrame 网址", + "unsupportedProtocol": "提供的URL使用了不支持的协议。请使用({supportedProtocols})中的一个", "noBrowerSupport": "您的浏览器不支持 iframe。请更新您的浏览器。" } }, "smartHome-entityState": { + "name": "实体状态", + "description": "显示实体状态并可选切换", "option": { "entityId": { "label": "实体 ID" + }, + "displayName": { + "label": "显示名称" + }, + "entityUnit": { + "label": "实体单位" + }, + "clickable": { + "label": "可单击" } } }, "smartHome-executeAutomation": { + "name": "执行自动化", + "description": "一键触发自动化操作", "option": { "displayName": { "label": "显示名称" @@ -348,13 +1315,28 @@ "automationId": { "label": "自动化 ID" } + }, + "spotlightAction": { + "run": "运行 {name}" } }, "calendar": { "name": "日历", + "description": "在日历视图中显示某个相对时间段内的集成事件", "option": { "releaseType": { - "label": "Radarr发布类型" + "label": "Radarr 发布类型", + "options": { + "inCinemas": "院线放映中", + "digitalRelease": "数字发行", + "physicalRelease": "物理发布" + } + }, + "filterPastMonths": { + "label": "开始于" + }, + "filterFutureMonths": { + "label": "结束于" } } }, @@ -362,8 +1344,25 @@ "name": "天气", "description": "显示指定位置的当前天气信息。", "option": { + "isFormatFahrenheit": { + "label": "华氏温度" + }, "location": { "label": "天气位置" + }, + "showCity": { + "label": "显示城市" + }, + "hasForecast": { + "label": "显示预报" + }, + "forecastDayCount": { + "label": "预报天数", + "description": "当小部件不够宽时,显示的天数减少" + }, + "dateFormat": { + "label": "日期格式", + "description": "日期应该是什么样的" } }, "kind": { @@ -385,8 +1384,17 @@ }, "indexerManager": { "name": "索引器管理状态", + "description": "索引器状态", + "option": { + "openIndexerSiteInNewTab": { + "label": "在新标签中打开索引器站点" + } + }, "title": "索引器管理", - "testAll": "测试全部" + "testAll": "测试全部", + "error": { + "internalServerError": "获取索引器状态失败" + } }, "healthMonitoring": { "name": "系统健康监测", @@ -396,7 +1404,7 @@ "label": "CPU 温度(华氏度)" }, "cpu": { - "label": "显示CPU信息" + "label": "显示 CPU 信息" }, "memory": { "label": "显示内存信息" @@ -406,20 +1414,60 @@ } }, "popover": { - "available": "可用" + "information": "信息", + "processor": "处理器:{cpuModelName}", + "memory": "内存:{memory} GiB", + "memoryAvailable": "可用:{memoryAvailable}GiB ({percent}%)", + "version": "版本:{version}", + "uptime": "运行时间:{months} 月,{days} 天,{hours} 时,{minutes} 分", + "loadAverage": "平均负载:", + "minute": "1 分钟", + "minutes": "{count} 分钟", + "used": "已使用", + "available": "可用", + "lastSeen": "最近状态更新:{lastSeen}" + }, + "memory": {}, + "error": { + "internalServerError": "获取健康状态失败" } }, "common": { "location": { + "query": "城市/邮编", + "latitude": "纬度", + "longitude": "经度", + "disabledTooltip": "请输入城市或邮编", + "unknownLocation": "未知位置", "search": "搜索", "table": { - "header": {}, - "action": {}, + "header": { + "city": "城市", + "country": "国家", + "coordinates": "坐标", + "population": "人口" + }, + "action": { + "select": "选择 {city},{countryCode}" + }, "population": { "fallback": "未知" } } - } + }, + "integration": { + "noData": "没有找到集成", + "description": "点击 创建一个新的集成" + }, + "app": { + "noData": "未找到应用", + "description": "点击 创建一个新的应用" + }, + "error": { + "noIntegration": "未选择集成", + "noData": "没有可用的集成数据" + }, + "option": {} }, "video": { "name": "视频流", @@ -429,33 +1477,134 @@ "label": "订阅网址" }, "hasAutoPlay": { - "label": "自动播放" + "label": "自动播放", + "description": "自动播放仅在因浏览器限制而被静音时生效" + }, + "isMuted": { + "label": "静音" + }, + "hasControls": { + "label": "显示控件" } + }, + "error": { + "noUrl": "没有提供视频 URL", + "forYoutubeUseIframe": "YouTube 视频使用 iframe 选项" + } + }, + "mediaServer": { + "name": "当前媒体服务流", + "description": "显示媒体服务器上的当前流", + "option": {}, + "items": { + "user": "用户", + "name": "名称", + "id": "ID" } }, "downloads": { + "name": "下载客户端", + "description": "允许您查看和管理来自Torrent 和 Usenet 客户端的下载。", + "option": { + "columns": { + "label": "显示的列" + }, + "enableRowSorting": { + "label": "启用项目排序" + }, + "defaultSort": { + "label": "默认排序列" + }, + "descendingDefaultSort": { + "label": "倒序" + }, + "showCompletedUsenet": { + "label": "显示标记为已完成的 usenet 条目" + }, + "showCompletedTorrent": { + "label": "显示标记为已完成的 Torrent 条目" + }, + "activeTorrentThreshold": { + "label": "隐藏在此阈值下已完成的 Torrent (kiB/s)" + }, + "categoryFilter": { + "label": "要过滤的分类/标签" + }, + "filterIsWhitelist": { + "label": "以白名单过滤" + }, + "applyFilterToRatio": { + "label": "使用过滤器来计算比率" + } + }, + "errors": { + "noColumns": "在项目中选择列", + "noCommunications": "无法从集成中加载数据" + }, "items": { + "actions": { + "columnTitle": "控制" + }, "added": { - "detailsTitle": "日期已添加" + "columnTitle": "已添加", + "detailsTitle": "添加日期" + }, + "category": { + "columnTitle": "扩展的", + "detailsTitle": "分类(额外信息)" }, "downSpeed": { "columnTitle": "下载", "detailsTitle": "下载速度" }, + "index": { + "columnTitle": "#", + "detailsTitle": "客户端中的当前索引" + }, + "id": { + "columnTitle": "ID" + }, "integration": { "columnTitle": "集成" }, + "name": { + "columnTitle": "作业名称" + }, "progress": { - "columnTitle": "进度" + "columnTitle": "进度", + "detailsTitle": "下载进度" }, "ratio": { - "columnTitle": "分享率" + "columnTitle": "分享率", + "detailsTitle": "Torrent 比率(接收/发送)" + }, + "received": { + "columnTitle": "总下载", + "detailsTitle": "总下载量" + }, + "sent": { + "columnTitle": "总上传", + "detailsTitle": "总上传量" + }, + "size": { + "columnTitle": "文件大小", + "detailsTitle": "文件大小" }, "state": { - "columnTitle": "状态" + "columnTitle": "状态", + "detailsTitle": "作业状态" + }, + "time": { + "columnTitle": "完成时间", + "detailsTitle": "完成时间" + }, + "type": { + "columnTitle": "类型", + "detailsTitle": "下载客户端类型" }, "upSpeed": { - "columnTitle": "上传" + "columnTitle": "上传", + "detailsTitle": "上传速度" } }, "states": { @@ -463,62 +1612,318 @@ "queued": "排队中", "paused": "已暂停", "completed": "已完成", - "unknown": "未知" - } + "failed": "已失败", + "processing": "处理中", + "leeching": "吸血", + "stalled": "已暂停", + "unknown": "未知", + "seeding": "做种中" + }, + "actions": { + "clients": { + "modalTitle": "下载客户列表", + "pause": "暂停所有客户端/项目", + "resume": "恢复所有客户端/项目" + }, + "client": { + "pause": "暂停客户端", + "resume": "恢复客户端" + }, + "item": { + "pause": "暂停项目", + "resume": "恢复项目", + "delete": { + "title": "删除项目", + "modalTitle": "确定要删除此作业?", + "entry": "删除条目", + "entryAndFiles": "删除条目和文件(s)" + } + } + }, + "globalRatio": "全局比率" }, "mediaRequests-requestList": { + "name": "媒体请求列表", "description": "查看 Overr 或 Jellyseerr 实例中的所有媒体请求列表", "option": { "linksTargetNewTab": { "label": "在新标签页中打开链接" } }, + "pending": { + "approve": "批准请求", + "approving": "正在批准请求...", + "decline": "拒绝请求" + }, "availability": { "unknown": "未知", + "pending": "等待处理", + "processing": "处理中", "partiallyAvailable": "部分", "available": "可用" - } + }, + "toBeDetermined": "待定" }, "mediaRequests-requestStats": { + "name": "媒体请求状态", "description": "您的媒体请求统计", + "option": {}, "titles": { "stats": { "main": "媒体统计", "approved": "已经批准", "pending": "等待批准", + "processing": "处理中", + "declined": "已拒绝", + "available": "已可用", "tv": "电视请求", "movie": "电影请求", "total": "请求总计" }, "users": { - "main": "用户排行" + "main": "用户排行", + "requests": "请求" + } + } + }, + "mediaTranscoding": { + "name": "媒体转码", + "description": "您的媒体转码的统计、当前队列和工作状态", + "option": { + "defaultView": { + "label": "默认视图" + }, + "queuePageSize": { + "label": "队列页面大小" + } + }, + "tab": { + "workers": "工作中", + "queue": "队列", + "statistics": "统计" + }, + "currentIndex": "{total} 的 {start}-{end}", + "healthCheck": { + "title": "健康检查", + "queued": "排队中", + "status": { + "healthy": "健康", + "unhealthy": "不良" + } + }, + "panel": { + "statistics": { + "empty": "空", + "transcodes": "转码", + "transcodesCount": "转码:{value}", + "healthChecksCount": "健康检查:{value}", + "filesCount": "文件数:{value}", + "savedSpace": "节省空间:{value}", + "healthChecks": "健康检查", + "videoCodecs": "编码", + "videoContainers": "容器", + "videoResolutions": "分辨率" + }, + "workers": { + "empty": "空", + "table": { + "file": "文件", + "eta": "剩余时间", + "progress": "进度", + "transcode": "转码", + "healthCheck": "健康检查" + } + }, + "queue": { + "empty": "空", + "table": { + "file": "文件", + "size": "大小", + "transcode": "转码", + "healthCheck": "健康检查" + } + } + } + }, + "rssFeed": { + "name": "RSS 订阅", + "description": "监视和显示一个或多个通用 RSS、ATOM 或 JSON 源", + "option": { + "feedUrls": { + "label": "订阅网址" + }, + "enableRtl": { + "label": "启用 RTL" + }, + "textLinesClamp": { + "label": "描述线条" + }, + "maximumAmountPosts": { + "label": "帖子数量限制" } } } }, + "widgetPreview": { + "toggle": { + "enabled": "启用编辑模式", + "disabled": "禁用编辑模式" + }, + "dimensions": { + "title": "更改尺寸" + } + }, "board": { "action": { + "duplicate": { + "title": "复制面板", + "message": "这将复制面板{name}及其所有内容。如果组件引用了不允许使用的集成,它们将被删除。", + "notification": { + "success": { + "title": "面板已复制", + "message": "面板已成功复制" + }, + "error": { + "title": "无法复制面板", + "message": "无法复制面板" + } + } + }, + "edit": { + "notification": { + "success": { + "title": "成功应用更改", + "message": "面板保存成功" + }, + "error": { + "title": "无法应用更改", + "message": "面板无法保存" + } + }, + "confirmLeave": { + "title": "未保存更改", + "message": "您有尚未保存的更改。您确定要离开吗?" + } + }, "oldImport": { + "label": "从 1.0.0 之前的 Homarr 导入", + "notification": { + "success": { + "title": "导入成功", + "message": "面板导入成功" + }, + "error": { + "title": "导入失败", + "message": "无法导入面板,请检查日志以获取更多详情" + } + }, "form": { + "file": { + "label": "选择 JSON 文件", + "invalidError": "无效的配置文件" + }, "apps": { - "label": "应用" + "label": "应用", + "avoidDuplicates": { + "label": "避免重复", + "description": "忽略已经存在具有相同链接的应用" + }, + "onlyImportApps": { + "label": "仅导入应用", + "description": "只添加应用,面板需要手动重新创建" + } + }, + "name": { + "label": "面板名称" }, "screenSize": { + "label": "屏幕大小", + "description": "在1.0之前的版本中,有三种不同的模式,所以你可以根据屏幕大小选择列的数量。", "option": { "sm": "小号", "md": "中号", "lg": "大号" } + }, + "sidebarBehavior": { + "label": "侧边栏行为", + "description": "侧边栏在1.0中被删除了,您可以选择其中的项目应该发生什么。", + "option": { + "lastSection": { + "label": "最后部分", + "description": "侧边栏将显示在最后一部分的下方" + }, + "removeItems": { + "label": "删除项目", + "description": "侧边栏中包含的项目将被删除" + } + } } } } }, "field": { + "pageTitle": { + "label": "页面标题" + }, + "metaTitle": { + "label": "Meta 标题" + }, + "logoImageUrl": { + "label": "Logo 图像 URL" + }, + "faviconImageUrl": { + "label": "Favicon 图像 URL" + }, + "backgroundImageUrl": { + "label": "背景图片 URL" + }, "backgroundImageAttachment": { - "label": "背景图片附件" + "label": "背景图片附件", + "option": { + "fixed": { + "label": "固定", + "description": "背景保持不变。" + }, + "scroll": { + "label": "滚动", + "description": "用鼠标滚动背景。" + } + } + }, + "backgroundImageRepeat": { + "label": "背景图片重复", + "option": { + "repeat": { + "label": "重复", + "description": "为了覆盖整个背景图像绘画区域,所需的图像会被重复使用。" + }, + "no-repeat": { + "label": "不重复", + "description": "图像不重复,无法填充整个空间。" + }, + "repeat-x": { + "label": "水平重复", + "description": "与“重复”相同,但仅在水平轴上。" + }, + "repeat-y": { + "label": "垂直重复", + "description": "与“重复”相同,但仅在垂直轴上。" + } + } }, "backgroundImageSize": { - "label": "背景图像大小" + "label": "背景图像大小", + "option": { + "cover": { + "label": "封面", + "description": "通过裁剪过多的空间,将图像缩放得尽可能小以覆盖整个窗口。" + }, + "contain": { + "label": "包含", + "description": "将图像缩放在容器内,但不裁剪或拉伸图像。" + } + } }, "primaryColor": { "label": "主体色" @@ -526,32 +1931,62 @@ "secondaryColor": { "label": "辅助色" }, + "opacity": { + "label": "不透明度" + }, "customCss": { - "description": "只推荐有经验的用户使用 CSS 自定义面板" + "label": "自定义此面板的 css", + "description": "只推荐有经验的用户使用 CSS 自定义面板", + "customClassesAlert": { + "title": "自定义类别", + "description": "您可以在每个项目的高级选项中添加自定义类别到您的面板项目并在上面的自定义 CSS 中使用它们。" + } + }, + "columnCount": { + "label": "列数" }, "name": { "label": "名称" }, "isPublic": { - "label": "公开" + "label": "公开", + "description": "每个人都可以访问公共面板,即使没有账户。" } }, + "content": { + "metaTitle": "{boardName} 面板" + }, "setting": { + "title": "{boardName} 面板设置", "section": { "general": { - "title": "通用" + "title": "通用", + "unrecognizedLink": "提供的链接未被识别,无法预览,但它可能仍然有效。" }, "layout": { - "title": "显示布局" + "title": "布局" }, "background": { "title": "背景" }, + "color": { + "title": "配色" + }, + "customCss": { + "title": "自定义 css" + }, "access": { + "title": "访问控制", "permission": { "item": { "view": { "label": "查看面板" + }, + "modify": { + "label": "修改面板" + }, + "full": { + "label": "完全访问" } } } @@ -559,42 +1994,126 @@ "dangerZone": { "title": "危险", "action": { - "delete": { + "rename": { + "label": "重命名面板", + "description": "更改名称将会破坏到此面板的任何链接。", + "button": "更改名字", + "modal": { + "title": "重命名面板" + } + }, + "visibility": { + "label": "更改面板可见性", + "description": { + "public": "此面板目前是公开的。", + "private": "此面板目前是私有的。" + }, + "button": { + "public": "设为私有", + "private": "设为公开" + }, "confirm": { - "title": "删除面板" + "public": { + "title": "设为私有面板", + "description": "您确定要将此面板设置为私有吗?这将隐藏在公众面前的面板。方可的链接将会断开。" + }, + "private": { + "title": "设为公开面板", + "description": "您确定要公开这个面板吗?这将使所有人都可以访问面板。" + } + } + }, + "delete": { + "label": "删除面板", + "description": "面板一旦删除就无法恢复. 请谨慎操作.", + "button": "删除面板", + "confirm": { + "title": "删除面板", + "description": "您确定要删除此面板吗?这将永久删除面板及其所有内容。" } } } } } + }, + "error": { + "noBoard": { + "title": "欢迎使用 Homarr", + "description": "一个时尚、现代的仪表盘,让你的所有应用和服务触手可及。", + "link": "创建您的第一个面板", + "notice": "要使这个页面消失,请创建一个面板并将其设置为主面板" + }, + "notFound": { + "title": "找不到面板", + "description": "未找到指定的面板,或者您没有访问权限。", + "link": "查看全部面板", + "notice": "如果您认为链接应该可以访问,请检查链接或联系管理员" + }, + "homeBoard": { + "title": "没有主面板", + "admin": { + "description": "您还没有为服务器设置主面板。", + "link": "配置服务器主面板", + "notice": "要使此页面消失,请为服务器设置主面板" + }, + "user": { + "description": "您尚未设置主面板。", + "link": "配置您的首页", + "notice": "要使此页面消失,请在您的偏好设置中指定主面板" + }, + "anonymous": { + "description": "服务器管理员尚未设置主面板。", + "link": "查看公共面板", + "notice": "要使这个页面消失,请服务器管理员为服务器设置一个主面板" + } + } } }, "management": { + "metaTitle": "管理中心", + "title": { + "morning": "{username},早上好呀 !", + "afternoon": "{username},下午好呀 !", + "evening": "{username},晚上好呀 !" + }, + "notFound": { + "title": "未找到", + "text": "找不到请求的资源" + }, "navbar": { "items": { "home": "首页", "boards": "面板", "apps": "应用", + "integrations": "集成", + "searchEngies": "搜索", + "medias": "媒体", "users": { "label": "用户", "items": { - "manage": "管理中心", - "invites": "邀请" + "manage": "管理", + "invites": "邀请", + "groups": "群组" } }, "tools": { "label": "工具", "items": { "docker": "Docker", - "api": "API" + "logs": "日志", + "api": "API", + "certificates": "", + "tasks": "任务" } }, "settings": "设置", "help": { "label": "帮助", "items": { - "documentation": "文档", - "discord": "Discord 社区" + "documentation": "帮助文档", + "submitIssue": "提交问题", + "discord": "Discord 社区", + "sourceCode": "源码仓库" } }, "about": "关于" @@ -606,30 +2125,58 @@ "board": "面板", "user": "用户", "invite": "邀请", - "app": "应用" + "integration": "集成", + "app": "应用", + "group": "群组" }, "statisticLabel": { - "boards": "面板" + "boards": "面板", + "resources": "资源", + "authentication": "认证", + "authorization": "认证" } }, "board": { "title": "您的面板", "action": { + "new": { + "label": "新建面板" + }, + "open": { + "label": "打开面板" + }, "settings": { "label": "设置" }, "setHomeBoard": { + "label": "设置为您的首页", "badge": { - "label": "首页" + "label": "首页", + "tooltip": "此面板将显示为您的主面板" } }, + "setMobileHomeBoard": { + "label": "设置为您的手机面板", + "badge": { + "label": "手机", + "tooltip": "此面板将显示为您的手机面板" + } + }, + "duplicate": { + "label": "复制面板" + }, "delete": { "label": "永久删除", "confirm": { - "title": "删除面板" + "title": "删除面板", + "description": "确认删除面板 {name} 吗?" } } }, + "visibility": { + "public": "此面板是公开的", + "private": "此面板是私有的" + }, "modal": { "createBoard": { "field": { @@ -640,11 +2187,25 @@ } } }, + "media": { + "includeFromAllUsers": "包含来自所有用户的媒体" + }, "user": { + "back": "返回用户", + "fieldsDisabledExternalProvider": "某些字段被禁用,因为它们是由外部认证提供者管理的。", "setting": { "general": { "title": "通用", "item": { + "language": "语言与地区", + "board": { + "title": "主面板", + "type": { + "general": "通用", + "mobile": "手机" + } + }, + "defaultSearchEngine": "默认搜索引擎", "firstDayOfWeek": "一周的第一天", "accessibility": "无障碍服务" } @@ -660,22 +2221,51 @@ "metaTitle": "管理用户", "title": "用户" }, + "edit": { + "metaTitle": "编辑用户 {username}" + }, "create": { "metaTitle": "创建用户", + "title": "创建新用户", "step": { + "personalInformation": { + "label": "个人资料" + }, "security": { "label": "安全" + }, + "groups": { + "label": "群组", + "title": "选择用户应该属于的用户组", + "description": "{everyoneGroup} 用户组被分配给所有用户,不能被删除。" + }, + "review": { + "label": "预览" + }, + "completed": { + "title": "创建用户" + }, + "error": { + "title": "用户创建失败" } + }, + "action": { + "createAnother": "创建另一个用户", + "back": "返回用户列表" } }, "invite": { "title": "管理用户邀请", "action": { "new": { + "title": "新建邀请", "description": "过期后,邀请会失效,被邀请的收件人将无法创建账号。" }, "copy": { - "link": "邀请链接" + "title": "复制邀请", + "description": "您的邀请已生成。在此模式关闭后,您将无法再复制此链接。如果你不想再邀请这个人,你可以随时删除这个邀请。", + "link": "邀请链接", + "button": "复制并关闭" }, "delete": { "title": "删除邀请", @@ -693,56 +2283,234 @@ "label": "过期时间" }, "token": { - "label": "Token" + "label": "秘钥" } } } }, "group": { + "back": "返回用户组", "setting": { "general": { - "title": "通用" + "title": "通用", + "owner": "所有者", + "ownerOfGroup": "该组的所有者", + "ownerOfGroupDeleted": "此用户组的所有者已被删除。它目前没有所有者。" + }, + "members": { + "title": "成员", + "search": "查找成员", + "notFound": "没有找到成员" + }, + "permissions": { + "title": "权限", + "form": { + "unsavedChanges": "你有未保存的更改 !" + } } } }, "settings": { - "title": "设置" + "title": "设置", + "notification": { + "success": { + "message": "设置保存成功" + }, + "error": { + "message": "无法保存设置" + } + }, + "section": { + "analytics": { + "title": "分析", + "general": { + "title": "发送匿名分析", + "text": "Homarr 将使用开源软件 Umami 发送匿名分析。它从不收集任何个人信息,因此完全符合 GDPR 和 CCPA 要求。我们鼓励您启用分析,因为它可以帮助我们的开源团队识别问题并确定待办事项的优先级。" + }, + "widgetData": { + "title": "组件数据", + "text": "发送您已配置的组件(及其数量)。不包括URL、名称或任何其他数据。" + }, + "integrationData": { + "title": "集成数据", + "text": "发送您已配置的集成(及其数量)。不包括URL、名称或任何其他数据。" + }, + "usersData": { + "title": "用户数据", + "text": "发送用户数量以及您是否激活了SSO" + } + }, + "crawlingAndIndexing": { + "title": "爬取和索引", + "warning": "启用或禁用这里的任何设置将严重影响搜索引擎如何索引和抓取你的页面。任何设置都是一个请求,是否应用这些设置取决于爬虫。任何修改可能需要数天或数周才能申请。一些设置可能是搜索引擎特定的。", + "noIndex": { + "title": "不要索引", + "text": "不要在搜索引擎上索引网站,也不要在任何搜索结果中显示。" + }, + "noFollow": { + "title": "不要追踪", + "text": "索引时不要追踪任何链接。禁用此功能将导致爬虫程序试图跟踪Homarr上的所有链接。" + }, + "noTranslate": { + "title": "不要翻译", + "text": "当站点语言可能不是用户想要阅读的语言时,谷歌将在搜索结果中显示一个翻译链接" + }, + "noSiteLinksSearchBox": { + "title": "没有站点链接搜索框", + "text": "谷歌将与爬取的链接以及其他直接链接构建一个搜索框。启用此功能将要求谷歌禁用该框。" + } + }, + "board": { + "title": "面板", + "homeBoard": { + "label": "全局主面板", + "mobileLabel": "全局手机面板", + "description": "只有公共面板可供选择" + } + }, + "search": { + "title": "搜索", + "defaultSearchEngine": { + "label": "全局默认搜索引擎", + "description": "无法在这里选择集成搜索引擎" + } + }, + "appearance": { + "title": "外观", + "defaultColorScheme": { + "label": "默认配色方案", + "options": { + "light": "日间", + "dark": "暗黑" + } + } + }, + "culture": { + "title": "区域", + "defaultLocale": { + "label": "默认语言" + } + } + } }, "tool": { "tasks": { + "title": "任务", "status": { + "idle": "空闲", "running": "运行中", "error": "错误" }, "job": { + "minecraftServerStatus": { + "label": "Minecraft 服务状态" + }, + "iconsUpdater": { + "label": "图标更新" + }, + "analytics": { + "label": "分析" + }, + "smartHomeEntityState": { + "label": "智能家居实体状态" + }, + "ping": { + "label": "Pings" + }, "mediaServer": { "label": "媒体服务" }, - "mediaRequests": { - "label": "媒体请求" + "mediaOrganizer": { + "label": "媒体组织者" + }, + "downloads": { + "label": "正在下载" + }, + "mediaRequestStats": { + "label": "媒体请求统计" + }, + "mediaRequestList": { + "label": "媒体请求列表" + }, + "rssFeeds": { + "label": "RSS订阅" + }, + "indexerManager": { + "label": "索引器管理" + }, + "healthMonitoring": { + "label": "健康监测" + }, + "dnsHole": { + "label": "DNS Hole 数据" + }, + "sessionCleanup": { + "label": "会话清理" + }, + "updateChecker": { + "label": "更新检查" + }, + "mediaTranscoding": { + "label": "媒体转码" } } }, "api": { "title": "API", + "modal": { + "createApiToken": { + "title": "API 令牌已创建", + "description": "已创建API令牌。小心,这个令牌在数据库中是加密的,永远不会再传输给您。如果您丢失了这个令牌,您将无法再检索这个特定的令牌。", + "button": "复制并关闭" + } + }, "tab": { "documentation": { "label": "文档" }, "apiKey": { + "label": "认证", + "title": "API 密钥", + "button": { + "createApiToken": "创建 API 令牌" + }, "table": { "header": { - "id": "ID" + "id": "ID", + "createdBy": "创建者" } } } } } + }, + "about": { + "version": "版本 {version}", + "text": "Homarr 是个由社区推动的开源项目,是志愿者们在维护。多亏了这些人,从 2021 年起,Homarr 这个项目一直在发展壮大。我们的团队来自许多不同的国家,完全远程工作,在空闲时间无偿搞 Homarr 这个项目。", + "accordion": { + "contributors": { + "title": "贡献人员", + "subtitle": "{count} 人在维护代码和 Homarr" + }, + "translators": { + "title": "翻译人员", + "subtitle": "{count} 名人员翻译了许多语言" + }, + "libraries": { + "title": "相关的库", + "subtitle": "{count} 个相关的库在 Homarr 代码中被使用" + } + } } } }, "docker": { "title": "容器", + "table": { + "updated": "已更新 {when}", + "search": "搜索 {count} 容器", + "selected": "{totalCount} 容器的 {selectCount}" + }, "field": { "name": { "label": "名称" @@ -754,7 +2522,9 @@ "running": "运行中", "paused": "已暂停", "restarting": "正在重启", - "removing": "删除中" + "exited": "已退出", + "removing": "删除中", + "dead": "废弃" } }, "containerImage": { @@ -766,27 +2536,118 @@ }, "action": { "start": { - "label": "开始" + "label": "开始", + "notification": { + "success": { + "title": "容器已启动", + "message": "容器已成功启动" + }, + "error": { + "title": "容器未启动", + "message": "容器无法启动" + } + } }, "stop": { - "label": "停止" + "label": "停止", + "notification": { + "success": { + "title": "容器已停止", + "message": "容器已成功停止" + }, + "error": { + "title": "容器未停止", + "message": "容器无法停止" + } + } }, "restart": { - "label": "重启" + "label": "重启", + "notification": { + "success": { + "title": "容器已重启", + "message": "容器已成功重启" + }, + "error": { + "title": "容器未重启", + "message": "容器无法重启" + } + } }, "remove": { - "label": "删除" + "label": "删除", + "notification": { + "success": { + "title": "容器已删除", + "message": "容器已成功删除" + }, + "error": { + "title": "容器未删除", + "message": "容器无法删除" + } + } + }, + "refresh": { + "label": "刷新", + "notification": { + "success": { + "title": "容器已刷新", + "message": "您正在查看最新数据" + }, + "error": { + "title": "容器未刷新", + "message": "刷新容器时出现错误" + } + } + }, + "addToHomarr": { + "label": "添加到 Homarr", + "notification": { + "success": { + "title": "已添加到 Homarr", + "message": "所选应用已被添加到 Homarr" + }, + "error": { + "title": "无法添加到 Homarr", + "message": "所选应用无法添加到 Homarr" + } + }, + "modal": { + "title": "将 docker 容器添加到 Homarr" + } } + }, + "error": { + "internalServerError": "获取 Docker 容器失败" } }, "permission": { + "title": "权限", + "userSelect": { + "title": "添加用户权限" + }, + "groupSelect": { + "title": "添加用户组权限" + }, "tab": { - "user": "用户" + "user": "用户", + "group": "群组", + "inherited": "继承的用户组" }, "field": { "user": { "label": "用户" + }, + "group": { + "label": "群组" + }, + "permission": { + "label": "权限" } + }, + "action": { + "saveUser": "保存用户权限", + "saveGroup": "保存用户组权限" } }, "navigationStructure": { @@ -796,17 +2657,31 @@ "label": "面板" }, "integrations": { + "label": "集成", "edit": { "label": "编辑" + }, + "new": { + "label": "新建" } }, "search-engines": { + "label": "搜索引擎", + "new": { + "label": "新建" + }, "edit": { "label": "编辑" } }, + "medias": { + "label": "媒体" + }, "apps": { "label": "应用", + "new": { + "label": "新建" + }, "edit": { "label": "编辑" } @@ -819,6 +2694,9 @@ "general": "通用", "security": "安全", "board": "面板", + "groups": { + "label": "群组" + }, "invites": { "label": "邀请" } @@ -827,6 +2705,12 @@ "label": "工具", "docker": { "label": "Docker" + }, + "logs": { + "label": "日志" + }, + "certificates": { + "label": "" } }, "settings": { @@ -838,23 +2722,152 @@ } }, "search": { + "placeholder": "搜索任意内容", + "nothingFound": "没有找到", + "error": { + "fetch": "获取数据时发生错误。" + }, "mode": { "appIntegrationBoard": { + "help": "搜索应用、集成或面板", "group": { "app": { - "title": "应用" + "title": "应用", + "children": { + "action": { + "open": { + "label": "打开应用网址" + }, + "edit": { + "label": "编辑应用" + } + }, + "detail": { + "title": "为应用选择一个动作" + } + } }, "board": { - "title": "面板" + "title": "面板", + "children": { + "action": { + "open": { + "label": "打开面板" + }, + "homeBoard": { + "label": "设置为主面板" + }, + "mobileBoard": { + "label": "设置为手机面板" + }, + "settings": { + "label": "打开设置" + } + }, + "detail": { + "title": "为面板选择一个动作" + } + } + }, + "integration": { + "title": "集成" } } }, + "command": { + "help": "启用命令模式", + "group": { + "localCommand": { + "title": "本地命令" + }, + "globalCommand": { + "title": "全局命令", + "option": { + "colorScheme": { + "light": "切换到日间模式", + "dark": "切换到暗黑模式" + }, + "language": { + "label": "更改语言", + "children": { + "detail": { + "title": "选择你的首选语言" + } + } + }, + "newBoard": { + "label": "创建面板" + }, + "importBoard": { + "label": "导入面板" + }, + "newApp": { + "label": "创建应用" + }, + "newIntegration": { + "label": "创建集成", + "children": { + "detail": { + "title": "选择您想要创建的集成类型" + } + } + }, + "newUser": { + "label": "创建新用户" + }, + "newInvite": { + "label": "创建新邀请" + }, + "newGroup": { + "label": "创建新用户组" + } + } + } + } + }, + "media": { + "requestMovie": "请求电影", + "requestSeries": "请求电视节目", + "openIn": "在 {kind} 中打开" + }, "external": { + "help": "使用外部搜索引擎", "group": { "searchEngine": { + "title": "搜索引擎", + "children": { + "action": { + "search": { + "label": "使用“{name}”搜索" + } + }, + "detail": { + "title": "为搜索引起选择一个动作" + }, + "searchResults": { + "title": "选择搜索结果进行操作" + } + }, "option": { + "google": { + "name": "谷歌", + "description": "使用 Google 搜索网络" + }, + "bing": { + "name": "Bing", + "description": "使用 Bing 搜索网络" + }, + "duckduckgo": { + "name": "DuckDuckGo", + "description": "用 DuckDuckGo 搜索网络" + }, "torrent": { - "name": "Torrents" + "name": "种子", + "description": "在 Torrentdownloads.pro 上搜索种子。" + }, + "youTube": { + "name": "YouTube", + "description": "在 YouTube 上搜索视频" } } } @@ -862,12 +2875,18 @@ }, "help": { "group": { + "mode": { + "title": "模式" + }, "help": { "title": "帮助", "option": { "documentation": { "label": "文档" }, + "submitIssue": { + "label": "提交问题" + }, "discord": { "label": "Discord 社区" } @@ -875,35 +2894,256 @@ } } }, + "home": { + "group": { + "search": { + "title": "搜索", + "option": { + "other": { + "label": "使用另一个搜索引擎搜索" + }, + "no-default": { + "label": "没有默认的搜索引擎", + "description": "在首选项中设置默认搜索引擎" + }, + "search": { + "label": "用{name}搜索“{query}”" + }, + "from-integration": { + "description": "输入内容以搜索" + } + } + }, + "local": { + "title": "本地结果" + } + } + }, "page": { + "help": "搜索页面", "group": { "page": { + "title": "页", "option": { + "manageHome": { + "label": "管理首页" + }, + "manageBoard": { + "label": "管理面板" + }, + "manageApp": { + "label": "管理应用" + }, + "manageIntegration": { + "label": "管理集成" + }, + "manageSearchEngine": { + "label": "管理搜索引擎" + }, + "manageMedia": { + "label": "管理媒体" + }, "manageUser": { "label": "管理用户" }, + "manageInvite": { + "label": "管理邀请" + }, + "manageGroup": { + "label": "管理用户组" + }, + "manageDocker": { + "label": "管理 docker" + }, + "manageApi": { + "label": "Swagger API" + }, + "manageLog": { + "label": "查看日志" + }, + "manageTask": { + "label": "管理任务" + }, + "manageSettings": { + "label": "全局设置" + }, "about": { "label": "关于" }, + "homeBoard": { + "label": "主面板" + }, "preferences": { - "label": "您的首选项" + "label": "偏好设置" } } } } }, "userGroup": { + "help": "搜索用户或用户组", "group": { "user": { - "title": "用户" + "title": "用户", + "children": { + "action": { + "detail": { + "label": "显示用户详情" + } + }, + "detail": { + "title": "为用户选择一个动作" + } + } + }, + "group": { + "title": "群组", + "children": { + "action": { + "detail": { + "label": "显示用户组详情" + }, + "manageMember": { + "label": "管理成员" + }, + "managePermission": { + "label": "管理权限" + } + }, + "detail": { + "title": "为用户组选择一个动作" + } + } } } } }, "engine": { + "search": "查找搜索引擎", "field": { "name": { "label": "名称" + }, + "short": { + "label": "短的" + }, + "urlTemplate": { + "label": "URL搜索模板" + }, + "description": { + "label": "描述" + } + }, + "page": { + "list": { + "title": "搜索引擎", + "noResults": { + "title": "还没有搜索引擎", + "action": "创建您的第一个搜索引擎" + }, + "interactive": "交互,使用集成" + }, + "create": { + "title": "创建搜索引擎", + "notification": { + "success": { + "title": "搜索引擎已创建", + "message": "搜索引擎已成功创建" + }, + "error": { + "title": "没有创建搜索引擎", + "message": "这个搜索引擎不能被创建" + } + } + }, + "edit": { + "title": "编辑搜索引擎", + "notification": { + "success": { + "title": "成功应用更改", + "message": "搜索引擎已成功保存" + }, + "error": { + "title": "无法应用更改", + "message": "无法保存搜索引擎" + } + }, + "configControl": "配置", + "searchEngineType": { + "generic": "通用", + "fromIntegration": "来自集成" + } + }, + "delete": { + "title": "删除搜索引擎", + "message": "确认删除搜索引擎 {name} 吗'?", + "notification": { + "success": { + "title": "搜索引擎已删除", + "message": "搜索引擎已成功删除" + }, + "error": { + "title": "搜索引擎没有删除", + "message": "这个搜索引擎不能被删除" + } + } + } + }, + "media": { + "request": { + "modal": { + "title": "请求 “{name}”", + "table": { + "header": { + "season": "季", + "episodes": "集" + } + }, + "button": { + "send": "发送请求" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } } } } diff --git a/packages/translation/src/lang/cr.json b/packages/translation/src/lang/cr.json new file mode 100644 index 000000000..562a7f558 --- /dev/null +++ b/packages/translation/src/lang/cr.json @@ -0,0 +1,2968 @@ +{ + "init": { + "step": { + "start": { + "title": "crwdns4538:0crwdne4538:0", + "subtitle": "crwdns4540:0crwdne4540:0", + "description": "crwdns4542:0crwdne4542:0", + "action": { + "scratch": "crwdns4544:0crwdne4544:0", + "importOldmarr": "crwdns4546:0crwdne4546:0" + } + }, + "import": { + "title": "crwdns4548:0crwdne4548:0", + "subtitle": "crwdns4550:0crwdne4550:0", + "dropzone": { + "title": "crwdns4552:0crwdne4552:0", + "description": "crwdns4554:0crwdne4554:0" + }, + "fileInfo": { + "action": { + "change": "crwdns4556:0crwdne4556:0" + } + }, + "importSettings": { + "title": "crwdns4558:0crwdne4558:0", + "description": "crwdns4560:0crwdne4560:0" + }, + "boardSelection": { + "title": "crwdns4562:0{count}crwdne4562:0", + "description": "crwdns4564:0crwdne4564:0", + "action": { + "selectAll": "crwdns4566:0crwdne4566:0", + "unselectAll": "crwdns4568:0crwdne4568:0" + } + }, + "summary": { + "title": "crwdns4570:0crwdne4570:0", + "description": "crwdns4572:0crwdne4572:0", + "action": { + "import": "crwdns4574:0crwdne4574:0" + }, + "entities": { + "apps": "crwdns4576:0crwdne4576:0", + "boards": "crwdns4578:0crwdne4578:0", + "integrations": "crwdns4580:0crwdne4580:0", + "credentialUsers": "crwdns4582:0crwdne4582:0" + } + }, + "tokenModal": { + "title": "crwdns4584:0crwdne4584:0", + "field": { + "token": { + "label": "crwdns4586:0crwdne4586:0", + "description": "crwdns4588:0crwdne4588:0" + } + }, + "notification": { + "error": { + "title": "crwdns4590:0crwdne4590:0", + "message": "crwdns4592:0crwdne4592:0" + } + } + } + }, + "user": { + "title": "crwdns4594:0crwdne4594:0", + "subtitle": "crwdns4596:0crwdne4596:0", + "notification": { + "success": { + "title": "crwdns4598:0crwdne4598:0", + "message": "crwdns4600:0crwdne4600:0" + }, + "error": { + "title": "crwdns4602:0crwdne4602:0" + } + } + }, + "group": { + "title": "crwdns4604:0crwdne4604:0", + "subtitle": "crwdns4606:0crwdne4606:0", + "form": { + "name": { + "label": "crwdns4608:0crwdne4608:0", + "description": "crwdns4610:0crwdne4610:0" + } + } + }, + "settings": { + "title": "crwdns4612:0crwdne4612:0", + "subtitle": "crwdns4614:0crwdne4614:0" + }, + "finish": { + "title": "crwdns4616:0crwdne4616:0", + "subtitle": "crwdns4618:0crwdne4618:0", + "description": "crwdns4620:0crwdne4620:0", + "action": { + "goToBoard": "crwdns4622:0{name}crwdne4622:0", + "createBoard": "crwdns4624:0crwdne4624:0", + "inviteUser": "crwdns4626:0crwdne4626:0", + "docs": "crwdns4628:0crwdne4628:0" + } + } + }, + "backToStart": "crwdns4630:0crwdne4630:0" + }, + "user": { + "title": "crwdns4632:0crwdne4632:0", + "name": "crwdns4634:0crwdne4634:0", + "page": { + "login": { + "title": "crwdns4636:0crwdne4636:0", + "subtitle": "crwdns4638:0crwdne4638:0" + }, + "invite": { + "title": "crwdns4640:0crwdne4640:0", + "subtitle": "crwdns4642:0crwdne4642:0", + "description": "crwdns4644:0{username}crwdne4644:0" + }, + "init": { + "title": "crwdns4646:0crwdne4646:0", + "subtitle": "crwdns4648:0crwdne4648:0" + } + }, + "field": { + "email": { + "label": "crwdns4650:0crwdne4650:0", + "verified": "crwdns4652:0crwdne4652:0" + }, + "username": { + "label": "crwdns4654:0crwdne4654:0" + }, + "password": { + "label": "crwdns4656:0crwdne4656:0", + "requirement": { + "length": "crwdns4658:0crwdne4658:0", + "lowercase": "crwdns4660:0crwdne4660:0", + "uppercase": "crwdns4662:0crwdne4662:0", + "number": "crwdns4664:0crwdne4664:0", + "special": "crwdns4666:0crwdne4666:0" + } + }, + "passwordConfirm": { + "label": "crwdns4668:0crwdne4668:0" + }, + "previousPassword": { + "label": "crwdns4670:0crwdne4670:0" + }, + "homeBoard": { + "label": "crwdns4672:0crwdne4672:0" + }, + "pingIconsEnabled": { + "label": "crwdns4674:0crwdne4674:0" + } + }, + "error": { + "usernameTaken": "crwdns4676:0crwdne4676:0" + }, + "action": { + "login": { + "label": "crwdns4678:0crwdne4678:0", + "labelWith": "crwdns4680:0{provider}crwdne4680:0", + "notification": { + "success": { + "title": "crwdns4682:0crwdne4682:0", + "message": "crwdns4684:0crwdne4684:0" + }, + "error": { + "title": "crwdns4686:0crwdne4686:0", + "message": "crwdns4688:0crwdne4688:0" + } + }, + "forgotPassword": { + "label": "crwdns4690:0crwdne4690:0", + "description": "crwdns4692:0crwdne4692:0" + } + }, + "register": { + "label": "crwdns4694:0crwdne4694:0", + "notification": { + "success": { + "title": "crwdns4696:0crwdne4696:0", + "message": "crwdns4698:0crwdne4698:0" + }, + "error": { + "title": "crwdns4700:0crwdne4700:0", + "message": "crwdns4702:0crwdne4702:0" + } + } + }, + "create": "crwdns4704:0crwdne4704:0", + "changePassword": { + "label": "crwdns4706:0crwdne4706:0", + "notification": { + "success": { + "message": "crwdns4708:0crwdne4708:0" + }, + "error": { + "message": "crwdns4710:0crwdne4710:0" + } + } + }, + "changeHomeBoard": { + "notification": { + "success": { + "message": "crwdns4712:0crwdne4712:0" + }, + "error": { + "message": "crwdns4714:0crwdne4714:0" + } + } + }, + "changeFirstDayOfWeek": { + "notification": { + "success": { + "message": "crwdns4716:0crwdne4716:0" + }, + "error": { + "message": "crwdns4718:0crwdne4718:0" + } + } + }, + "changePingIconsEnabled": { + "notification": { + "success": { + "message": "crwdns4720:0crwdne4720:0" + }, + "error": { + "message": "crwdns4722:0crwdne4722:0" + } + } + }, + "manageAvatar": { + "changeImage": { + "label": "crwdns4724:0crwdne4724:0", + "notification": { + "success": { + "message": "crwdns4726:0crwdne4726:0" + }, + "error": { + "message": "crwdns4728:0crwdne4728:0" + }, + "toLarge": { + "title": "crwdns4730:0crwdne4730:0", + "message": "crwdns4732:0{size}crwdne4732:0" + } + } + }, + "removeImage": { + "label": "crwdns4734:0crwdne4734:0", + "confirm": "crwdns4736:0crwdne4736:0", + "notification": { + "success": { + "message": "crwdns4738:0crwdne4738:0" + }, + "error": { + "message": "crwdns4740:0crwdne4740:0" + } + } + } + }, + "editProfile": { + "notification": { + "success": { + "message": "crwdns4742:0crwdne4742:0" + }, + "error": { + "message": "crwdns4744:0crwdne4744:0" + } + } + }, + "delete": { + "label": "crwdns4746:0crwdne4746:0", + "description": "crwdns4748:0crwdne4748:0", + "confirm": "crwdns4750:0{username}crwdne4750:0" + }, + "select": { + "label": "crwdns4752:0crwdne4752:0", + "notFound": "crwdns4754:0crwdne4754:0" + }, + "transfer": { + "label": "crwdns4756:0crwdne4756:0" + } + } + }, + "group": { + "title": "crwdns4758:0crwdne4758:0", + "name": "crwdns4760:0crwdne4760:0", + "search": "crwdns4762:0crwdne4762:0", + "field": { + "name": "crwdns4764:0crwdne4764:0", + "members": "crwdns4766:0crwdne4766:0" + }, + "permission": { + "admin": { + "title": "crwdns4768:0crwdne4768:0", + "item": { + "admin": { + "label": "crwdns4770:0crwdne4770:0", + "description": "crwdns4772:0crwdne4772:0" + } + } + }, + "app": { + "title": "crwdns4774:0crwdne4774:0", + "item": { + "create": { + "label": "crwdns4776:0crwdne4776:0", + "description": "crwdns4778:0crwdne4778:0" + }, + "use-all": { + "label": "crwdns4780:0crwdne4780:0", + "description": "crwdns4782:0crwdne4782:0" + }, + "modify-all": { + "label": "crwdns4784:0crwdne4784:0", + "description": "crwdns4786:0crwdne4786:0" + }, + "full-all": { + "label": "crwdns4788:0crwdne4788:0", + "description": "crwdns4790:0crwdne4790:0" + } + } + }, + "board": { + "title": "crwdns4792:0crwdne4792:0", + "item": { + "create": { + "label": "crwdns4794:0crwdne4794:0", + "description": "crwdns4796:0crwdne4796:0" + }, + "view-all": { + "label": "crwdns4798:0crwdne4798:0", + "description": "crwdns4800:0crwdne4800:0" + }, + "modify-all": { + "label": "crwdns4802:0crwdne4802:0", + "description": "crwdns4804:0crwdne4804:0" + }, + "full-all": { + "label": "crwdns4806:0crwdne4806:0", + "description": "crwdns4808:0crwdne4808:0" + } + } + }, + "integration": { + "title": "crwdns4810:0crwdne4810:0", + "item": { + "create": { + "label": "crwdns4812:0crwdne4812:0", + "description": "crwdns4814:0crwdne4814:0" + }, + "use-all": { + "label": "crwdns4816:0crwdne4816:0", + "description": "crwdns4818:0crwdne4818:0" + }, + "interact-all": { + "label": "crwdns4820:0crwdne4820:0", + "description": "crwdns4822:0crwdne4822:0" + }, + "full-all": { + "label": "crwdns4824:0crwdne4824:0", + "description": "crwdns4826:0crwdne4826:0" + } + } + }, + "media": { + "title": "crwdns4828:0crwdne4828:0", + "item": { + "upload": { + "label": "crwdns4830:0crwdne4830:0", + "description": "crwdns4832:0crwdne4832:0" + }, + "view-all": { + "label": "crwdns4834:0crwdne4834:0", + "description": "crwdns4836:0crwdne4836:0" + }, + "full-all": { + "label": "crwdns4838:0crwdne4838:0", + "description": "crwdns4840:0crwdne4840:0" + } + } + }, + "other": { + "title": "crwdns4842:0crwdne4842:0", + "item": { + "view-logs": { + "label": "crwdns4844:0crwdne4844:0", + "description": "crwdns4846:0crwdne4846:0" + } + } + }, + "search-engine": { + "title": "crwdns4848:0crwdne4848:0", + "item": { + "create": { + "label": "crwdns4850:0crwdne4850:0", + "description": "crwdns4852:0crwdne4852:0" + }, + "modify-all": { + "label": "crwdns4854:0crwdne4854:0", + "description": "crwdns4856:0crwdne4856:0" + }, + "full-all": { + "label": "crwdns4858:0crwdne4858:0", + "description": "crwdns4860:0crwdne4860:0" + } + } + } + }, + "memberNotice": { + "mixed": "crwdns4862:0crwdne4862:0", + "external": "crwdns4864:0crwdne4864:0" + }, + "reservedNotice": { + "message": "crwdns4866:0crwdne4866:0" + }, + "action": { + "create": { + "label": "crwdns4868:0crwdne4868:0", + "notification": { + "success": { + "message": "crwdns4870:0crwdne4870:0" + }, + "error": { + "message": "crwdns4872:0crwdne4872:0" + } + } + }, + "transfer": { + "label": "crwdns4874:0crwdne4874:0", + "description": "crwdns4876:0crwdne4876:0", + "confirm": "crwdns4878:0{name}crwdnd4878:0{username}crwdne4878:0", + "notification": { + "success": { + "message": "crwdns4880:0{group}crwdnd4880:0{user}crwdne4880:0" + }, + "error": { + "message": "crwdns4882:0crwdne4882:0" + } + } + }, + "addMember": { + "label": "crwdns4884:0crwdne4884:0" + }, + "removeMember": { + "label": "crwdns4886:0crwdne4886:0", + "confirm": "crwdns4888:0{user}crwdne4888:0" + }, + "delete": { + "label": "crwdns4890:0crwdne4890:0", + "description": "crwdns4892:0crwdne4892:0", + "confirm": "crwdns4894:0{name}crwdne4894:0", + "notification": { + "success": { + "message": "crwdns4896:0{name}crwdne4896:0" + }, + "error": { + "message": "crwdns4898:0{name}crwdne4898:0" + } + } + }, + "changePermissions": { + "notification": { + "success": { + "title": "crwdns4900:0crwdne4900:0", + "message": "crwdns4902:0crwdne4902:0" + }, + "error": { + "title": "crwdns4904:0crwdne4904:0", + "message": "crwdns4906:0crwdne4906:0" + } + } + }, + "update": { + "notification": { + "success": { + "message": "crwdns4908:0{name}crwdne4908:0" + }, + "error": { + "message": "crwdns4910:0{name}crwdne4910:0" + } + } + }, + "select": { + "label": "crwdns4912:0crwdne4912:0", + "notFound": "crwdns4914:0crwdne4914:0" + } + } + }, + "app": { + "page": { + "list": { + "title": "crwdns4916:0crwdne4916:0", + "noResults": { + "title": "crwdns4918:0crwdne4918:0", + "action": "crwdns4920:0crwdne4920:0" + } + }, + "create": { + "title": "crwdns4922:0crwdne4922:0", + "notification": { + "success": { + "title": "crwdns4924:0crwdne4924:0", + "message": "crwdns4926:0crwdne4926:0" + }, + "error": { + "title": "crwdns4928:0crwdne4928:0", + "message": "crwdns4930:0crwdne4930:0" + } + } + }, + "edit": { + "title": "crwdns4932:0crwdne4932:0", + "notification": { + "success": { + "title": "crwdns4934:0crwdne4934:0", + "message": "crwdns4936:0crwdne4936:0" + }, + "error": { + "title": "crwdns4938:0crwdne4938:0", + "message": "crwdns4940:0crwdne4940:0" + } + } + }, + "delete": { + "title": "crwdns4942:0crwdne4942:0", + "message": "crwdns4944:0{name}crwdne4944:0", + "notification": { + "success": { + "title": "crwdns4946:0crwdne4946:0", + "message": "crwdns4948:0crwdne4948:0" + }, + "error": { + "title": "crwdns4950:0crwdne4950:0", + "message": "crwdns4952:0crwdne4952:0" + } + } + } + }, + "field": { + "name": { + "label": "crwdns4954:0crwdne4954:0" + }, + "description": { + "label": "crwdns4956:0crwdne4956:0" + }, + "url": { + "label": "crwdns4958:0crwdne4958:0" + } + }, + "action": { + "select": { + "label": "crwdns4960:0crwdne4960:0", + "notFound": "crwdns4962:0crwdne4962:0" + } + } + }, + "integration": { + "page": { + "list": { + "title": "crwdns4964:0crwdne4964:0", + "search": "crwdns4966:0crwdne4966:0", + "noResults": { + "title": "crwdns4968:0crwdne4968:0" + } + }, + "create": { + "title": "crwdns4970:0{name}crwdne4970:0", + "notification": { + "success": { + "title": "crwdns4972:0crwdne4972:0", + "message": "crwdns4974:0crwdne4974:0" + }, + "error": { + "title": "crwdns4976:0crwdne4976:0", + "message": "crwdns4978:0crwdne4978:0" + } + } + }, + "edit": { + "title": "crwdns4980:0{name}crwdne4980:0", + "notification": { + "success": { + "title": "crwdns4982:0crwdne4982:0", + "message": "crwdns4984:0crwdne4984:0" + }, + "error": { + "title": "crwdns4986:0crwdne4986:0", + "message": "crwdns4988:0crwdne4988:0" + } + } + }, + "delete": { + "title": "crwdns4990:0crwdne4990:0", + "message": "crwdns4992:0{name}crwdne4992:0", + "notification": { + "success": { + "title": "crwdns4994:0crwdne4994:0", + "message": "crwdns4996:0crwdne4996:0" + }, + "error": { + "title": "crwdns4998:0crwdne4998:0", + "message": "crwdns5000:0crwdne5000:0" + } + } + } + }, + "field": { + "name": { + "label": "crwdns5002:0crwdne5002:0" + }, + "url": { + "label": "crwdns5004:0crwdne5004:0" + } + }, + "action": { + "create": "crwdns5006:0crwdne5006:0" + }, + "testConnection": { + "action": { + "create": "crwdns5008:0crwdne5008:0", + "edit": "crwdns5010:0crwdne5010:0" + }, + "alertNotice": "crwdns5012:0crwdne5012:0", + "notification": { + "success": { + "title": "crwdns5014:0crwdne5014:0", + "message": "crwdns5016:0crwdne5016:0" + }, + "invalidUrl": { + "title": "crwdns5018:0crwdne5018:0", + "message": "crwdns5020:0crwdne5020:0" + }, + "secretNotDefined": { + "title": "crwdns5022:0crwdne5022:0", + "message": "crwdns5024:0crwdne5024:0" + }, + "invalidCredentials": { + "title": "crwdns5026:0crwdne5026:0", + "message": "crwdns5028:0crwdne5028:0" + }, + "commonError": { + "title": "crwdns5030:0crwdne5030:0", + "message": "crwdns5032:0crwdne5032:0" + }, + "badRequest": { + "title": "crwdns5034:0crwdne5034:0", + "message": "crwdns5036:0crwdne5036:0" + }, + "unauthorized": { + "title": "crwdns5038:0crwdne5038:0", + "message": "crwdns5040:0crwdne5040:0" + }, + "forbidden": { + "title": "crwdns5042:0crwdne5042:0", + "message": "crwdns5044:0crwdne5044:0" + }, + "notFound": { + "title": "crwdns5046:0crwdne5046:0", + "message": "crwdns5048:0crwdne5048:0" + }, + "internalServerError": { + "title": "crwdns5050:0crwdne5050:0", + "message": "crwdns5052:0crwdne5052:0" + }, + "serviceUnavailable": { + "title": "crwdns5054:0crwdne5054:0", + "message": "crwdns5056:0crwdne5056:0" + }, + "connectionAborted": { + "title": "crwdns5058:0crwdne5058:0", + "message": "crwdns5060:0crwdne5060:0" + }, + "domainNotFound": { + "title": "crwdns5062:0crwdne5062:0", + "message": "crwdns5064:0crwdne5064:0" + }, + "connectionRefused": { + "title": "crwdns5066:0crwdne5066:0", + "message": "crwdns5068:0crwdne5068:0" + }, + "invalidJson": { + "title": "crwdns5070:0crwdne5070:0", + "message": "crwdns5072:0crwdne5072:0" + }, + "wrongPath": { + "title": "crwdns5074:0crwdne5074:0", + "message": "crwdns5076:0crwdne5076:0" + } + } + }, + "secrets": { + "title": "crwdns5078:0crwdne5078:0", + "lastUpdated": "crwdns5080:0{date}crwdne5080:0", + "notSet": { + "label": "crwdns5082:0crwdne5082:0", + "tooltip": "crwdns5084:0crwdne5084:0" + }, + "secureNotice": "crwdns5086:0crwdne5086:0", + "reset": { + "title": "crwdns5088:0crwdne5088:0", + "message": "crwdns5090:0crwdne5090:0" + }, + "noSecretsRequired": { + "segmentTitle": "crwdns5092:0crwdne5092:0", + "text": "crwdns5094:0crwdne5094:0" + }, + "kind": { + "username": { + "label": "crwdns5096:0crwdne5096:0", + "newLabel": "crwdns5098:0crwdne5098:0" + }, + "apiKey": { + "label": "crwdns5100:0crwdne5100:0", + "newLabel": "crwdns5102:0crwdne5102:0" + }, + "password": { + "label": "crwdns5104:0crwdne5104:0", + "newLabel": "crwdns5106:0crwdne5106:0" + } + } + }, + "permission": { + "use": "crwdns5108:0crwdne5108:0", + "interact": "crwdns5110:0crwdne5110:0", + "full": "crwdns5112:0crwdne5112:0" + } + }, + "media": { + "plural": "crwdns5114:0crwdne5114:0", + "search": "crwdns5116:0crwdne5116:0", + "field": { + "name": "crwdns5118:0crwdne5118:0", + "size": "crwdns5120:0crwdne5120:0", + "creator": "crwdns5122:0crwdne5122:0" + }, + "action": { + "upload": { + "label": "crwdns5124:0crwdne5124:0", + "file": "crwdns5126:0crwdne5126:0", + "notification": { + "success": { + "message": "crwdns5128:0crwdne5128:0" + }, + "error": { + "message": "crwdns5130:0crwdne5130:0" + } + } + }, + "delete": { + "label": "crwdns5132:0crwdne5132:0", + "description": "crwdns5134:0crwdne5134:0", + "notification": { + "success": { + "message": "crwdns5136:0crwdne5136:0" + }, + "error": { + "message": "crwdns5138:0crwdne5138:0" + } + } + }, + "copy": { + "label": "crwdns5140:0crwdne5140:0" + } + } + }, + "common": { + "beta": "crwdns5142:0crwdne5142:0", + "error": "crwdns5144:0crwdne5144:0", + "action": { + "add": "crwdns5146:0crwdne5146:0", + "apply": "crwdns5148:0crwdne5148:0", + "backToOverview": "crwdns5150:0crwdne5150:0", + "create": "crwdns5152:0crwdne5152:0", + "edit": "crwdns5154:0crwdne5154:0", + "import": "crwdns5156:0crwdne5156:0", + "insert": "crwdns5158:0crwdne5158:0", + "remove": "crwdns5160:0crwdne5160:0", + "save": "crwdns5162:0crwdne5162:0", + "saveChanges": "crwdns5164:0crwdne5164:0", + "cancel": "crwdns5166:0crwdne5166:0", + "delete": "crwdns5168:0crwdne5168:0", + "discard": "crwdns5170:0crwdne5170:0", + "confirm": "crwdns5172:0crwdne5172:0", + "continue": "crwdns5174:0crwdne5174:0", + "previous": "crwdns5176:0crwdne5176:0", + "next": "crwdns5178:0crwdne5178:0", + "checkoutDocs": "crwdns5180:0crwdne5180:0", + "checkLogs": "crwdns5182:0crwdne5182:0", + "tryAgain": "crwdns5184:0crwdne5184:0", + "loading": "crwdns5186:0crwdne5186:0" + }, + "here": "crwdns5188:0crwdne5188:0", + "iconPicker": { + "label": "crwdns5190:0crwdne5190:0", + "header": "crwdns5192:0{countIcons}crwdne5192:0" + }, + "colorScheme": { + "options": { + "light": "crwdns5194:0crwdne5194:0", + "dark": "crwdns5196:0crwdne5196:0" + } + }, + "information": { + "min": "crwdns5198:0crwdne5198:0", + "max": "crwdns5200:0crwdne5200:0", + "days": "crwdns5202:0crwdne5202:0", + "hours": "crwdns5204:0crwdne5204:0", + "minutes": "crwdns5206:0crwdne5206:0" + }, + "notification": { + "create": { + "success": "crwdns5208:0crwdne5208:0", + "error": "crwdns5210:0crwdne5210:0" + }, + "delete": { + "success": "crwdns5212:0crwdne5212:0", + "error": "crwdns5214:0crwdne5214:0" + }, + "update": { + "success": "crwdns5216:0crwdne5216:0", + "error": "crwdns5218:0crwdne5218:0" + }, + "transfer": { + "success": "crwdns5220:0crwdne5220:0", + "error": "crwdns5222:0crwdne5222:0" + } + }, + "multiSelect": { + "placeholder": "crwdns5224:0crwdne5224:0" + }, + "multiText": { + "placeholder": "crwdns5226:0crwdne5226:0", + "addLabel": "crwdns5228:0{value}crwdne5228:0" + }, + "select": { + "placeholder": "crwdns5230:0crwdne5230:0", + "badge": { + "recommended": "crwdns5232:0crwdne5232:0" + } + }, + "userAvatar": { + "menu": { + "switchToDarkMode": "crwdns5234:0crwdne5234:0", + "switchToLightMode": "crwdns5236:0crwdne5236:0", + "management": "crwdns5238:0crwdne5238:0", + "preferences": "crwdns5240:0crwdne5240:0", + "logout": "crwdns5242:0crwdne5242:0", + "login": "crwdns5244:0crwdne5244:0", + "homeBoard": "crwdns5246:0crwdne5246:0", + "loggedOut": "crwdns5248:0crwdne5248:0", + "updateAvailable": "crwdns5250:0{countUpdates}crwdnd5250:0{tag}crwdne5250:0" + } + }, + "dangerZone": "crwdns5252:0crwdne5252:0", + "noResults": "crwdns5254:0crwdne5254:0", + "preview": { + "show": "crwdns5256:0crwdne5256:0", + "hide": "crwdns5258:0crwdne5258:0" + }, + "zod": { + "errors": { + "default": "crwdns5260:0crwdne5260:0", + "required": "crwdns5262:0crwdne5262:0", + "string": { + "startsWith": "crwdns5264:0{startsWith}crwdne5264:0", + "endsWith": "crwdns5266:0{endsWith}crwdne5266:0", + "includes": "crwdns5268:0{includes}crwdne5268:0", + "invalidEmail": "crwdns5270:0crwdne5270:0" + }, + "tooSmall": { + "string": "crwdns5272:0{minimum}crwdne5272:0", + "number": "crwdns5274:0{minimum}crwdne5274:0" + }, + "tooBig": { + "string": "crwdns5276:0{maximum}crwdne5276:0", + "number": "crwdns5278:0{maximum}crwdne5278:0" + }, + "custom": { + "passwordsDoNotMatch": "crwdns5280:0crwdne5280:0", + "passwordRequirements": "crwdns5282:0crwdne5282:0", + "boardAlreadyExists": "crwdns5284:0crwdne5284:0", + "invalidFileType": "crwdns5286:0{expected}crwdne5286:0", + "fileTooLarge": "crwdns5288:0{maxSize}crwdne5288:0", + "invalidConfiguration": "crwdns5290:0crwdne5290:0", + "groupNameTaken": "crwdns5292:0crwdne5292:0" + } + } + } + }, + "section": { + "dynamic": { + "action": { + "create": "crwdns5294:0crwdne5294:0", + "remove": "crwdns5296:0crwdne5296:0" + }, + "remove": { + "title": "crwdns5298:0crwdne5298:0", + "message": "crwdns5300:0crwdne5300:0" + } + }, + "category": { + "field": { + "name": { + "label": "crwdns5302:0crwdne5302:0" + } + }, + "action": { + "create": "crwdns5304:0crwdne5304:0", + "edit": "crwdns5306:0crwdne5306:0", + "remove": "crwdns5308:0crwdne5308:0", + "moveUp": "crwdns5310:0crwdne5310:0", + "moveDown": "crwdns5312:0crwdne5312:0", + "createAbove": "crwdns5314:0crwdne5314:0", + "createBelow": "crwdns5316:0crwdne5316:0" + }, + "create": { + "title": "crwdns5318:0crwdne5318:0", + "submit": "crwdns5320:0crwdne5320:0" + }, + "remove": { + "title": "crwdns5322:0crwdne5322:0", + "message": "crwdns5324:0{name}crwdne5324:0" + }, + "edit": { + "title": "crwdns5326:0crwdne5326:0", + "submit": "crwdns5328:0crwdne5328:0" + }, + "menu": { + "label": { + "create": "crwdns5330:0crwdne5330:0", + "changePosition": "crwdns5332:0crwdne5332:0" + } + } + } + }, + "item": { + "action": { + "create": "crwdns5334:0crwdne5334:0", + "import": "crwdns5336:0crwdne5336:0", + "edit": "crwdns5338:0crwdne5338:0", + "moveResize": "crwdns5340:0crwdne5340:0", + "duplicate": "crwdns5342:0crwdne5342:0", + "remove": "crwdns5344:0crwdne5344:0" + }, + "menu": { + "label": { + "settings": "crwdns5346:0crwdne5346:0" + } + }, + "create": { + "title": "crwdns5348:0crwdne5348:0", + "addToBoard": "crwdns5350:0crwdne5350:0" + }, + "moveResize": { + "title": "crwdns5352:0crwdne5352:0", + "field": { + "width": { + "label": "crwdns5354:0crwdne5354:0" + }, + "height": { + "label": "crwdns5356:0crwdne5356:0" + }, + "xOffset": { + "label": "crwdns5358:0crwdne5358:0" + }, + "yOffset": { + "label": "crwdns5360:0crwdne5360:0" + } + } + }, + "edit": { + "title": "crwdns5362:0crwdne5362:0", + "advancedOptions": { + "label": "crwdns5364:0crwdne5364:0", + "title": "crwdns5366:0crwdne5366:0" + }, + "field": { + "integrations": { + "label": "crwdns5368:0crwdne5368:0" + }, + "customCssClasses": { + "label": "crwdns5370:0crwdne5370:0" + } + } + }, + "remove": { + "title": "crwdns5372:0crwdne5372:0", + "message": "crwdns5374:0crwdne5374:0" + } + }, + "widget": { + "app": { + "name": "crwdns5376:0crwdne5376:0", + "description": "crwdns5378:0crwdne5378:0", + "option": { + "appId": { + "label": "crwdns5380:0crwdne5380:0" + }, + "openInNewTab": { + "label": "crwdns5382:0crwdne5382:0" + }, + "showTitle": { + "label": "crwdns5384:0crwdne5384:0" + }, + "showDescriptionTooltip": { + "label": "crwdns5386:0crwdne5386:0" + }, + "pingEnabled": { + "label": "crwdns5388:0crwdne5388:0" + } + }, + "error": { + "notFound": { + "label": "crwdns5390:0crwdne5390:0", + "tooltip": "crwdns5392:0crwdne5392:0" + } + } + }, + "bookmarks": { + "name": "crwdns5394:0crwdne5394:0", + "description": "crwdns5396:0crwdne5396:0", + "option": { + "title": { + "label": "crwdns5398:0crwdne5398:0" + }, + "layout": { + "label": "crwdns5400:0crwdne5400:0", + "option": { + "row": { + "label": "crwdns5402:0crwdne5402:0" + }, + "column": { + "label": "crwdns5404:0crwdne5404:0" + }, + "grid": { + "label": "crwdns5406:0crwdne5406:0" + } + } + }, + "items": { + "label": "crwdns5408:0crwdne5408:0", + "add": "crwdns5410:0crwdne5410:0" + } + } + }, + "dnsHoleSummary": { + "name": "crwdns5412:0crwdne5412:0", + "description": "crwdns5414:0crwdne5414:0", + "option": { + "layout": { + "label": "crwdns5416:0crwdne5416:0", + "option": { + "row": { + "label": "crwdns5418:0crwdne5418:0" + }, + "column": { + "label": "crwdns5420:0crwdne5420:0" + }, + "grid": { + "label": "crwdns5422:0crwdne5422:0" + } + } + }, + "usePiHoleColors": { + "label": "crwdns5424:0crwdne5424:0" + } + }, + "error": { + "internalServerError": "crwdns5426:0crwdne5426:0", + "integrationsDisconnected": "crwdns5428:0crwdne5428:0" + }, + "data": { + "adsBlockedToday": "crwdns5430:0crwdne5430:0", + "adsBlockedTodayPercentage": "crwdns5432:0crwdne5432:0", + "dnsQueriesToday": "crwdns5434:0crwdne5434:0", + "domainsBeingBlocked": "crwdns5436:0crwdne5436:0" + } + }, + "dnsHoleControls": { + "name": "crwdns5438:0crwdne5438:0", + "description": "crwdns5440:0crwdne5440:0", + "option": { + "layout": { + "label": "crwdns5442:0crwdne5442:0", + "option": { + "row": { + "label": "crwdns5444:0crwdne5444:0" + }, + "column": { + "label": "crwdns5446:0crwdne5446:0" + }, + "grid": { + "label": "crwdns5448:0crwdne5448:0" + } + } + }, + "showToggleAllButtons": { + "label": "crwdns5450:0crwdne5450:0" + } + }, + "error": { + "internalServerError": "crwdns5452:0crwdne5452:0" + }, + "controls": { + "enableAll": "crwdns5454:0crwdne5454:0", + "disableAll": "crwdns5456:0crwdne5456:0", + "setTimer": "crwdns5458:0crwdne5458:0", + "set": "crwdns5460:0crwdne5460:0", + "enabled": "crwdns5462:0crwdne5462:0", + "disabled": "crwdns5464:0crwdne5464:0", + "processing": "crwdns5466:0crwdne5466:0", + "disconnected": "crwdns5468:0crwdne5468:0", + "hours": "crwdns5470:0crwdne5470:0", + "minutes": "crwdns5472:0crwdne5472:0", + "unlimited": "crwdns5474:0crwdne5474:0" + } + }, + "clock": { + "name": "crwdns5476:0crwdne5476:0", + "description": "crwdns5478:0crwdne5478:0", + "option": { + "customTitleToggle": { + "label": "crwdns5480:0crwdne5480:0", + "description": "crwdns5482:0crwdne5482:0" + }, + "customTitle": { + "label": "crwdns5484:0crwdne5484:0" + }, + "is24HourFormat": { + "label": "crwdns5486:0crwdne5486:0", + "description": "crwdns5488:0crwdne5488:0" + }, + "showSeconds": { + "label": "crwdns5490:0crwdne5490:0" + }, + "useCustomTimezone": { + "label": "crwdns5492:0crwdne5492:0" + }, + "timezone": { + "label": "crwdns5494:0crwdne5494:0", + "description": "crwdns5496:0crwdne5496:0" + }, + "showDate": { + "label": "crwdns5498:0crwdne5498:0" + }, + "dateFormat": { + "label": "crwdns5500:0crwdne5500:0", + "description": "crwdns5502:0crwdne5502:0" + } + } + }, + "notebook": { + "name": "crwdns5504:0crwdne5504:0", + "description": "crwdns5506:0crwdne5506:0", + "option": { + "showToolbar": { + "label": "crwdns5508:0crwdne5508:0" + }, + "allowReadOnlyCheck": { + "label": "crwdns5510:0crwdne5510:0" + }, + "content": { + "label": "crwdns5512:0crwdne5512:0" + } + }, + "controls": { + "bold": "crwdns5514:0crwdne5514:0", + "italic": "crwdns5516:0crwdne5516:0", + "strikethrough": "crwdns5518:0crwdne5518:0", + "underline": "crwdns5520:0crwdne5520:0", + "colorText": "crwdns5522:0crwdne5522:0", + "colorHighlight": "crwdns5524:0crwdne5524:0", + "code": "crwdns5526:0crwdne5526:0", + "clear": "crwdns5528:0crwdne5528:0", + "heading": "crwdns5530:0{level}crwdne5530:0", + "align": "crwdns5532:0{position}crwdne5532:0", + "blockquote": "crwdns5534:0crwdne5534:0", + "horizontalLine": "crwdns5536:0crwdne5536:0", + "bulletList": "crwdns5538:0crwdne5538:0", + "orderedList": "crwdns5540:0crwdne5540:0", + "checkList": "crwdns5542:0crwdne5542:0", + "increaseIndent": "crwdns5544:0crwdne5544:0", + "decreaseIndent": "crwdns5546:0crwdne5546:0", + "link": "crwdns5548:0crwdne5548:0", + "unlink": "crwdns5550:0crwdne5550:0", + "image": "crwdns5552:0crwdne5552:0", + "addTable": "crwdns5554:0crwdne5554:0", + "deleteTable": "crwdns5556:0crwdne5556:0", + "colorCell": "crwdns5558:0crwdne5558:0", + "mergeCell": "crwdns5560:0crwdne5560:0", + "addColumnLeft": "crwdns5562:0crwdne5562:0", + "addColumnRight": "crwdns5564:0crwdne5564:0", + "deleteColumn": "crwdns5566:0crwdne5566:0", + "addRowTop": "crwdns5568:0crwdne5568:0", + "addRowBelow": "crwdns5570:0crwdne5570:0", + "deleteRow": "crwdns5572:0crwdne5572:0" + }, + "align": { + "left": "crwdns5574:0crwdne5574:0", + "center": "crwdns5576:0crwdne5576:0", + "right": "crwdns5578:0crwdne5578:0" + }, + "popover": { + "clearColor": "crwdns5580:0crwdne5580:0", + "source": "crwdns5582:0crwdne5582:0", + "widthPlaceholder": "crwdns5584:0crwdne5584:0", + "columns": "crwdns5586:0crwdne5586:0", + "rows": "crwdns5588:0crwdne5588:0", + "width": "crwdns5590:0crwdne5590:0", + "height": "crwdns5592:0crwdne5592:0" + } + }, + "iframe": { + "name": "crwdns5594:0crwdne5594:0", + "description": "crwdns5596:0crwdne5596:0", + "option": { + "embedUrl": { + "label": "crwdns5598:0crwdne5598:0" + }, + "allowFullScreen": { + "label": "crwdns5600:0crwdne5600:0" + }, + "allowTransparency": { + "label": "crwdns5602:0crwdne5602:0" + }, + "allowScrolling": { + "label": "crwdns5604:0crwdne5604:0" + }, + "allowPayment": { + "label": "crwdns5606:0crwdne5606:0" + }, + "allowAutoPlay": { + "label": "crwdns5608:0crwdne5608:0" + }, + "allowMicrophone": { + "label": "crwdns5610:0crwdne5610:0" + }, + "allowCamera": { + "label": "crwdns5612:0crwdne5612:0" + }, + "allowGeolocation": { + "label": "crwdns5614:0crwdne5614:0" + } + }, + "error": { + "noUrl": "crwdns5616:0crwdne5616:0", + "noBrowerSupport": "crwdns5618:0crwdne5618:0" + } + }, + "smartHome-entityState": { + "name": "crwdns5620:0crwdne5620:0", + "description": "crwdns5622:0crwdne5622:0", + "option": { + "entityId": { + "label": "crwdns5624:0crwdne5624:0" + }, + "displayName": { + "label": "crwdns5626:0crwdne5626:0" + }, + "entityUnit": { + "label": "crwdns5628:0crwdne5628:0" + }, + "clickable": { + "label": "crwdns5630:0crwdne5630:0" + } + } + }, + "smartHome-executeAutomation": { + "name": "crwdns5632:0crwdne5632:0", + "description": "crwdns5634:0crwdne5634:0", + "option": { + "displayName": { + "label": "crwdns5636:0crwdne5636:0" + }, + "automationId": { + "label": "crwdns5638:0crwdne5638:0" + } + }, + "spotlightAction": { + "run": "crwdns5640:0{name}crwdne5640:0" + } + }, + "calendar": { + "name": "crwdns5642:0crwdne5642:0", + "description": "crwdns5644:0crwdne5644:0", + "option": { + "releaseType": { + "label": "crwdns5646:0crwdne5646:0", + "options": { + "inCinemas": "crwdns5648:0crwdne5648:0", + "digitalRelease": "crwdns5650:0crwdne5650:0", + "physicalRelease": "crwdns5652:0crwdne5652:0" + } + }, + "filterPastMonths": { + "label": "crwdns5654:0crwdne5654:0" + }, + "filterFutureMonths": { + "label": "crwdns5656:0crwdne5656:0" + } + } + }, + "weather": { + "name": "crwdns5658:0crwdne5658:0", + "description": "crwdns5660:0crwdne5660:0", + "option": { + "isFormatFahrenheit": { + "label": "crwdns5662:0crwdne5662:0" + }, + "location": { + "label": "crwdns5664:0crwdne5664:0" + }, + "showCity": { + "label": "crwdns5666:0crwdne5666:0" + }, + "hasForecast": { + "label": "crwdns5668:0crwdne5668:0" + }, + "forecastDayCount": { + "label": "crwdns5670:0crwdne5670:0", + "description": "crwdns5672:0crwdne5672:0" + }, + "dateFormat": { + "label": "crwdns5674:0crwdne5674:0", + "description": "crwdns5676:0crwdne5676:0" + } + }, + "kind": { + "clear": "crwdns5678:0crwdne5678:0", + "mainlyClear": "crwdns5680:0crwdne5680:0", + "fog": "crwdns5682:0crwdne5682:0", + "drizzle": "crwdns5684:0crwdne5684:0", + "freezingDrizzle": "crwdns5686:0crwdne5686:0", + "rain": "crwdns5688:0crwdne5688:0", + "freezingRain": "crwdns5690:0crwdne5690:0", + "snowFall": "crwdns5692:0crwdne5692:0", + "snowGrains": "crwdns5694:0crwdne5694:0", + "rainShowers": "crwdns5696:0crwdne5696:0", + "snowShowers": "crwdns5698:0crwdne5698:0", + "thunderstorm": "crwdns5700:0crwdne5700:0", + "thunderstormWithHail": "crwdns5702:0crwdne5702:0", + "unknown": "crwdns5704:0crwdne5704:0" + } + }, + "indexerManager": { + "name": "crwdns5706:0crwdne5706:0", + "description": "crwdns5708:0crwdne5708:0", + "option": { + "openIndexerSiteInNewTab": { + "label": "crwdns5710:0crwdne5710:0" + } + }, + "title": "crwdns5712:0crwdne5712:0", + "testAll": "crwdns5714:0crwdne5714:0", + "error": { + "internalServerError": "crwdns5716:0crwdne5716:0" + } + }, + "healthMonitoring": { + "name": "crwdns5718:0crwdne5718:0", + "description": "crwdns5720:0crwdne5720:0", + "option": { + "fahrenheit": { + "label": "crwdns5722:0crwdne5722:0" + }, + "cpu": { + "label": "crwdns5724:0crwdne5724:0" + }, + "memory": { + "label": "crwdns5726:0crwdne5726:0" + }, + "fileSystem": { + "label": "crwdns5728:0crwdne5728:0" + } + }, + "popover": { + "information": "crwdns5730:0crwdne5730:0", + "processor": "crwdns5732:0{cpuModelName}crwdne5732:0", + "memory": "crwdns5734:0{memory}crwdne5734:0", + "memoryAvailable": "crwdns5736:0{memoryAvailable}crwdnd5736:0{percent}crwdne5736:0", + "version": "crwdns5738:0{version}crwdne5738:0", + "uptime": "crwdns7008:0{months}crwdnd7008:0{days}crwdnd7008:0{hours}crwdnd7008:0{minutes}crwdne7008:0", + "loadAverage": "crwdns5742:0crwdne5742:0", + "minute": "crwdns5744:0crwdne5744:0", + "minutes": "crwdns5746:0{count}crwdne5746:0", + "used": "crwdns5748:0crwdne5748:0", + "available": "crwdns5750:0crwdne5750:0", + "lastSeen": "crwdns5752:0{lastSeen}crwdne5752:0" + }, + "memory": {}, + "error": { + "internalServerError": "crwdns5754:0crwdne5754:0" + } + }, + "common": { + "location": { + "query": "crwdns5756:0crwdne5756:0", + "latitude": "crwdns5758:0crwdne5758:0", + "longitude": "crwdns5760:0crwdne5760:0", + "disabledTooltip": "crwdns5762:0crwdne5762:0", + "unknownLocation": "crwdns5764:0crwdne5764:0", + "search": "crwdns5766:0crwdne5766:0", + "table": { + "header": { + "city": "crwdns5768:0crwdne5768:0", + "country": "crwdns5770:0crwdne5770:0", + "coordinates": "crwdns5772:0crwdne5772:0", + "population": "crwdns5774:0crwdne5774:0" + }, + "action": { + "select": "crwdns5776:0{city}crwdnd5776:0{countryCode}crwdne5776:0" + }, + "population": { + "fallback": "crwdns5778:0crwdne5778:0" + } + } + }, + "integration": { + "noData": "crwdns5780:0crwdne5780:0", + "description": "crwdns5782:0crwdne5782:0" + }, + "app": { + "noData": "crwdns5784:0crwdne5784:0", + "description": "crwdns5786:0crwdne5786:0" + }, + "error": { + "noIntegration": "crwdns5788:0crwdne5788:0", + "noData": "crwdns5790:0crwdne5790:0" + }, + "option": {} + }, + "video": { + "name": "crwdns5792:0crwdne5792:0", + "description": "crwdns5794:0crwdne5794:0", + "option": { + "feedUrl": { + "label": "crwdns5796:0crwdne5796:0" + }, + "hasAutoPlay": { + "label": "crwdns5798:0crwdne5798:0", + "description": "crwdns5800:0crwdne5800:0" + }, + "isMuted": { + "label": "crwdns5802:0crwdne5802:0" + }, + "hasControls": { + "label": "crwdns5804:0crwdne5804:0" + } + }, + "error": { + "noUrl": "crwdns5806:0crwdne5806:0", + "forYoutubeUseIframe": "crwdns5808:0crwdne5808:0" + } + }, + "mediaServer": { + "name": "crwdns5810:0crwdne5810:0", + "description": "crwdns5812:0crwdne5812:0", + "option": {}, + "items": { + "user": "crwdns7010:0crwdne7010:0", + "name": "crwdns7012:0crwdne7012:0", + "id": "crwdns7014:0crwdne7014:0" + } + }, + "downloads": { + "name": "crwdns5814:0crwdne5814:0", + "description": "crwdns5816:0crwdne5816:0", + "option": { + "columns": { + "label": "crwdns5818:0crwdne5818:0" + }, + "enableRowSorting": { + "label": "crwdns5820:0crwdne5820:0" + }, + "defaultSort": { + "label": "crwdns5822:0crwdne5822:0" + }, + "descendingDefaultSort": { + "label": "crwdns5824:0crwdne5824:0" + }, + "showCompletedUsenet": { + "label": "crwdns5826:0crwdne5826:0" + }, + "showCompletedTorrent": { + "label": "crwdns5828:0crwdne5828:0" + }, + "activeTorrentThreshold": { + "label": "crwdns5830:0crwdne5830:0" + }, + "categoryFilter": { + "label": "crwdns5832:0crwdne5832:0" + }, + "filterIsWhitelist": { + "label": "crwdns5834:0crwdne5834:0" + }, + "applyFilterToRatio": { + "label": "crwdns5836:0crwdne5836:0" + } + }, + "errors": { + "noColumns": "crwdns5838:0crwdne5838:0", + "noCommunications": "crwdns5840:0crwdne5840:0" + }, + "items": { + "actions": { + "columnTitle": "crwdns5842:0crwdne5842:0" + }, + "added": { + "columnTitle": "crwdns5844:0crwdne5844:0", + "detailsTitle": "crwdns5846:0crwdne5846:0" + }, + "category": { + "columnTitle": "crwdns5848:0crwdne5848:0", + "detailsTitle": "crwdns5850:0crwdne5850:0" + }, + "downSpeed": { + "columnTitle": "crwdns5852:0crwdne5852:0", + "detailsTitle": "crwdns5854:0crwdne5854:0" + }, + "index": { + "columnTitle": "crwdns5856:0crwdne5856:0", + "detailsTitle": "crwdns5858:0crwdne5858:0" + }, + "id": { + "columnTitle": "crwdns5860:0crwdne5860:0" + }, + "integration": { + "columnTitle": "crwdns5862:0crwdne5862:0" + }, + "name": { + "columnTitle": "crwdns5864:0crwdne5864:0" + }, + "progress": { + "columnTitle": "crwdns5866:0crwdne5866:0", + "detailsTitle": "crwdns5868:0crwdne5868:0" + }, + "ratio": { + "columnTitle": "crwdns5870:0crwdne5870:0", + "detailsTitle": "crwdns5872:0crwdne5872:0" + }, + "received": { + "columnTitle": "crwdns5874:0crwdne5874:0", + "detailsTitle": "crwdns5876:0crwdne5876:0" + }, + "sent": { + "columnTitle": "crwdns5878:0crwdne5878:0", + "detailsTitle": "crwdns5880:0crwdne5880:0" + }, + "size": { + "columnTitle": "crwdns5882:0crwdne5882:0", + "detailsTitle": "crwdns5884:0crwdne5884:0" + }, + "state": { + "columnTitle": "crwdns5886:0crwdne5886:0", + "detailsTitle": "crwdns5888:0crwdne5888:0" + }, + "time": { + "columnTitle": "crwdns5890:0crwdne5890:0", + "detailsTitle": "crwdns5892:0crwdne5892:0" + }, + "type": { + "columnTitle": "crwdns5894:0crwdne5894:0", + "detailsTitle": "crwdns5896:0crwdne5896:0" + }, + "upSpeed": { + "columnTitle": "crwdns5898:0crwdne5898:0", + "detailsTitle": "crwdns5900:0crwdne5900:0" + } + }, + "states": { + "downloading": "crwdns5902:0crwdne5902:0", + "queued": "crwdns5904:0crwdne5904:0", + "paused": "crwdns5906:0crwdne5906:0", + "completed": "crwdns5908:0crwdne5908:0", + "failed": "crwdns5910:0crwdne5910:0", + "processing": "crwdns5912:0crwdne5912:0", + "leeching": "crwdns5914:0crwdne5914:0", + "stalled": "crwdns5916:0crwdne5916:0", + "unknown": "crwdns5918:0crwdne5918:0", + "seeding": "crwdns5920:0crwdne5920:0" + }, + "actions": { + "clients": { + "modalTitle": "crwdns5922:0crwdne5922:0", + "pause": "crwdns5924:0crwdne5924:0", + "resume": "crwdns5926:0crwdne5926:0" + }, + "client": { + "pause": "crwdns5928:0crwdne5928:0", + "resume": "crwdns5930:0crwdne5930:0" + }, + "item": { + "pause": "crwdns5932:0crwdne5932:0", + "resume": "crwdns5934:0crwdne5934:0", + "delete": { + "title": "crwdns5936:0crwdne5936:0", + "modalTitle": "crwdns5938:0crwdne5938:0", + "entry": "crwdns5940:0crwdne5940:0", + "entryAndFiles": "crwdns5942:0crwdne5942:0" + } + } + }, + "globalRatio": "crwdns5944:0crwdne5944:0" + }, + "mediaRequests-requestList": { + "name": "crwdns5946:0crwdne5946:0", + "description": "crwdns5948:0crwdne5948:0", + "option": { + "linksTargetNewTab": { + "label": "crwdns5950:0crwdne5950:0" + } + }, + "pending": { + "approve": "crwdns5952:0crwdne5952:0", + "approving": "crwdns5954:0crwdne5954:0", + "decline": "crwdns5956:0crwdne5956:0" + }, + "availability": { + "unknown": "crwdns5958:0crwdne5958:0", + "pending": "crwdns5960:0crwdne5960:0", + "processing": "crwdns5962:0crwdne5962:0", + "partiallyAvailable": "crwdns5964:0crwdne5964:0", + "available": "crwdns5966:0crwdne5966:0" + }, + "toBeDetermined": "crwdns5968:0crwdne5968:0" + }, + "mediaRequests-requestStats": { + "name": "crwdns5970:0crwdne5970:0", + "description": "crwdns5972:0crwdne5972:0", + "option": {}, + "titles": { + "stats": { + "main": "crwdns5974:0crwdne5974:0", + "approved": "crwdns5976:0crwdne5976:0", + "pending": "crwdns5978:0crwdne5978:0", + "processing": "crwdns5980:0crwdne5980:0", + "declined": "crwdns5982:0crwdne5982:0", + "available": "crwdns5984:0crwdne5984:0", + "tv": "crwdns5986:0crwdne5986:0", + "movie": "crwdns5988:0crwdne5988:0", + "total": "crwdns5990:0crwdne5990:0" + }, + "users": { + "main": "crwdns5992:0crwdne5992:0", + "requests": "crwdns5994:0crwdne5994:0" + } + } + }, + "mediaTranscoding": { + "name": "crwdns5996:0crwdne5996:0", + "description": "crwdns5998:0crwdne5998:0", + "option": { + "defaultView": { + "label": "crwdns6000:0crwdne6000:0" + }, + "queuePageSize": { + "label": "crwdns6002:0crwdne6002:0" + } + }, + "tab": { + "workers": "crwdns6004:0crwdne6004:0", + "queue": "crwdns6006:0crwdne6006:0", + "statistics": "crwdns6008:0crwdne6008:0" + }, + "currentIndex": "crwdns6010:0{start}crwdnd6010:0{end}crwdnd6010:0{total}crwdne6010:0", + "healthCheck": { + "title": "crwdns6012:0crwdne6012:0", + "queued": "crwdns6014:0crwdne6014:0", + "status": { + "healthy": "crwdns6016:0crwdne6016:0", + "unhealthy": "crwdns6018:0crwdne6018:0" + } + }, + "panel": { + "statistics": { + "empty": "crwdns6020:0crwdne6020:0", + "transcodes": "crwdns6022:0crwdne6022:0", + "transcodesCount": "crwdns6024:0{value}crwdne6024:0", + "healthChecksCount": "crwdns6026:0{value}crwdne6026:0", + "filesCount": "crwdns6028:0{value}crwdne6028:0", + "savedSpace": "crwdns6030:0{value}crwdne6030:0", + "healthChecks": "crwdns6032:0crwdne6032:0", + "videoCodecs": "crwdns6034:0crwdne6034:0", + "videoContainers": "crwdns6036:0crwdne6036:0", + "videoResolutions": "crwdns6038:0crwdne6038:0" + }, + "workers": { + "empty": "crwdns6040:0crwdne6040:0", + "table": { + "file": "crwdns6042:0crwdne6042:0", + "eta": "crwdns6044:0crwdne6044:0", + "progress": "crwdns6046:0crwdne6046:0", + "transcode": "crwdns6048:0crwdne6048:0", + "healthCheck": "crwdns6050:0crwdne6050:0" + } + }, + "queue": { + "empty": "crwdns6052:0crwdne6052:0", + "table": { + "file": "crwdns6054:0crwdne6054:0", + "size": "crwdns6056:0crwdne6056:0", + "transcode": "crwdns6058:0crwdne6058:0", + "healthCheck": "crwdns6060:0crwdne6060:0" + } + } + } + }, + "rssFeed": { + "name": "crwdns6062:0crwdne6062:0", + "description": "crwdns6064:0crwdne6064:0", + "option": { + "feedUrls": { + "label": "crwdns6066:0crwdne6066:0" + }, + "enableRtl": { + "label": "crwdns6068:0crwdne6068:0" + }, + "textLinesClamp": { + "label": "crwdns6070:0crwdne6070:0" + }, + "maximumAmountPosts": { + "label": "crwdns6072:0crwdne6072:0" + } + } + } + }, + "widgetPreview": { + "toggle": { + "enabled": "crwdns6074:0crwdne6074:0", + "disabled": "crwdns6076:0crwdne6076:0" + }, + "dimensions": { + "title": "crwdns6078:0crwdne6078:0" + } + }, + "board": { + "action": { + "edit": { + "notification": { + "success": { + "title": "crwdns6080:0crwdne6080:0", + "message": "crwdns6082:0crwdne6082:0" + }, + "error": { + "title": "crwdns6084:0crwdne6084:0", + "message": "crwdns6086:0crwdne6086:0" + } + }, + "confirmLeave": { + "title": "crwdns6088:0crwdne6088:0", + "message": "crwdns6090:0crwdne6090:0" + } + }, + "oldImport": { + "label": "crwdns6092:0crwdne6092:0", + "notification": { + "success": { + "title": "crwdns6094:0crwdne6094:0", + "message": "crwdns6096:0crwdne6096:0" + }, + "error": { + "title": "crwdns6098:0crwdne6098:0", + "message": "crwdns6100:0crwdne6100:0" + } + }, + "form": { + "file": { + "label": "crwdns6102:0crwdne6102:0", + "invalidError": "crwdns6104:0crwdne6104:0" + }, + "apps": { + "label": "crwdns6106:0crwdne6106:0", + "avoidDuplicates": { + "label": "crwdns6108:0crwdne6108:0", + "description": "crwdns6110:0crwdne6110:0" + }, + "onlyImportApps": { + "label": "crwdns6112:0crwdne6112:0", + "description": "crwdns6114:0crwdne6114:0" + } + }, + "name": { + "label": "crwdns6116:0crwdne6116:0" + }, + "screenSize": { + "label": "crwdns6118:0crwdne6118:0", + "description": "crwdns6120:0crwdne6120:0", + "option": { + "sm": "crwdns6122:0crwdne6122:0", + "md": "crwdns6124:0crwdne6124:0", + "lg": "crwdns6126:0crwdne6126:0" + } + }, + "sidebarBehavior": { + "label": "crwdns6128:0crwdne6128:0", + "description": "crwdns6130:0crwdne6130:0", + "option": { + "lastSection": { + "label": "crwdns6132:0crwdne6132:0", + "description": "crwdns6134:0crwdne6134:0" + }, + "removeItems": { + "label": "crwdns6136:0crwdne6136:0", + "description": "crwdns6138:0crwdne6138:0" + } + } + } + } + } + }, + "field": { + "pageTitle": { + "label": "crwdns6140:0crwdne6140:0" + }, + "metaTitle": { + "label": "crwdns6142:0crwdne6142:0" + }, + "logoImageUrl": { + "label": "crwdns6144:0crwdne6144:0" + }, + "faviconImageUrl": { + "label": "crwdns6146:0crwdne6146:0" + }, + "backgroundImageUrl": { + "label": "crwdns6148:0crwdne6148:0" + }, + "backgroundImageAttachment": { + "label": "crwdns6150:0crwdne6150:0", + "option": { + "fixed": { + "label": "crwdns6152:0crwdne6152:0", + "description": "crwdns6154:0crwdne6154:0" + }, + "scroll": { + "label": "crwdns6156:0crwdne6156:0", + "description": "crwdns6158:0crwdne6158:0" + } + } + }, + "backgroundImageRepeat": { + "label": "crwdns6160:0crwdne6160:0", + "option": { + "repeat": { + "label": "crwdns6162:0crwdne6162:0", + "description": "crwdns6164:0crwdne6164:0" + }, + "no-repeat": { + "label": "crwdns6166:0crwdne6166:0", + "description": "crwdns6168:0crwdne6168:0" + }, + "repeat-x": { + "label": "crwdns6170:0crwdne6170:0", + "description": "crwdns6172:0crwdne6172:0" + }, + "repeat-y": { + "label": "crwdns6174:0crwdne6174:0", + "description": "crwdns6176:0crwdne6176:0" + } + } + }, + "backgroundImageSize": { + "label": "crwdns6178:0crwdne6178:0", + "option": { + "cover": { + "label": "crwdns6180:0crwdne6180:0", + "description": "crwdns6182:0crwdne6182:0" + }, + "contain": { + "label": "crwdns6184:0crwdne6184:0", + "description": "crwdns6186:0crwdne6186:0" + } + } + }, + "primaryColor": { + "label": "crwdns6188:0crwdne6188:0" + }, + "secondaryColor": { + "label": "crwdns6190:0crwdne6190:0" + }, + "opacity": { + "label": "crwdns6192:0crwdne6192:0" + }, + "customCss": { + "label": "crwdns6194:0crwdne6194:0", + "description": "crwdns6196:0crwdne6196:0", + "customClassesAlert": { + "title": "crwdns6198:0crwdne6198:0", + "description": "crwdns6200:0crwdne6200:0" + } + }, + "columnCount": { + "label": "crwdns6202:0crwdne6202:0" + }, + "name": { + "label": "crwdns6204:0crwdne6204:0" + }, + "isPublic": { + "label": "crwdns6206:0crwdne6206:0", + "description": "crwdns6208:0crwdne6208:0" + } + }, + "content": { + "metaTitle": "crwdns6210:0{boardName}crwdne6210:0" + }, + "setting": { + "title": "crwdns6212:0{boardName}crwdne6212:0", + "section": { + "general": { + "title": "crwdns6214:0crwdne6214:0", + "unrecognizedLink": "crwdns6216:0crwdne6216:0" + }, + "layout": { + "title": "crwdns6218:0crwdne6218:0" + }, + "background": { + "title": "crwdns6220:0crwdne6220:0" + }, + "color": { + "title": "crwdns6222:0crwdne6222:0" + }, + "customCss": { + "title": "crwdns6224:0crwdne6224:0" + }, + "access": { + "title": "crwdns6226:0crwdne6226:0", + "permission": { + "item": { + "view": { + "label": "crwdns6228:0crwdne6228:0" + }, + "modify": { + "label": "crwdns6230:0crwdne6230:0" + }, + "full": { + "label": "crwdns6232:0crwdne6232:0" + } + } + } + }, + "dangerZone": { + "title": "crwdns6234:0crwdne6234:0", + "action": { + "rename": { + "label": "crwdns6236:0crwdne6236:0", + "description": "crwdns6238:0crwdne6238:0", + "button": "crwdns6240:0crwdne6240:0", + "modal": { + "title": "crwdns6242:0crwdne6242:0" + } + }, + "visibility": { + "label": "crwdns6244:0crwdne6244:0", + "description": { + "public": "crwdns6246:0crwdne6246:0", + "private": "crwdns6248:0crwdne6248:0" + }, + "button": { + "public": "crwdns6250:0crwdne6250:0", + "private": "crwdns6252:0crwdne6252:0" + }, + "confirm": { + "public": { + "title": "crwdns6254:0crwdne6254:0", + "description": "crwdns6256:0crwdne6256:0" + }, + "private": { + "title": "crwdns6258:0crwdne6258:0", + "description": "crwdns6260:0crwdne6260:0" + } + } + }, + "delete": { + "label": "crwdns6262:0crwdne6262:0", + "description": "crwdns6264:0crwdne6264:0", + "button": "crwdns6266:0crwdne6266:0", + "confirm": { + "title": "crwdns6268:0crwdne6268:0", + "description": "crwdns6270:0crwdne6270:0" + } + } + } + } + } + }, + "error": { + "noBoard": { + "title": "crwdns6272:0crwdne6272:0", + "description": "crwdns6274:0crwdne6274:0", + "link": "crwdns6276:0crwdne6276:0", + "notice": "crwdns6278:0crwdne6278:0" + }, + "notFound": { + "title": "crwdns6280:0crwdne6280:0", + "description": "crwdns6282:0crwdne6282:0", + "link": "crwdns6284:0crwdne6284:0", + "notice": "crwdns6286:0crwdne6286:0" + }, + "homeBoard": { + "title": "crwdns6288:0crwdne6288:0", + "admin": { + "description": "crwdns6290:0crwdne6290:0", + "link": "crwdns6292:0crwdne6292:0", + "notice": "crwdns6294:0crwdne6294:0" + }, + "user": { + "description": "crwdns6296:0crwdne6296:0", + "link": "crwdns6298:0crwdne6298:0", + "notice": "crwdns6300:0crwdne6300:0" + }, + "anonymous": { + "description": "crwdns6302:0crwdne6302:0", + "link": "crwdns6304:0crwdne6304:0", + "notice": "crwdns6306:0crwdne6306:0" + } + } + } + }, + "management": { + "metaTitle": "crwdns6308:0crwdne6308:0", + "title": { + "morning": "crwdns6310:0{username}crwdne6310:0", + "afternoon": "crwdns6312:0{username}crwdne6312:0", + "evening": "crwdns6314:0{username}crwdne6314:0" + }, + "notFound": { + "title": "crwdns6316:0crwdne6316:0", + "text": "crwdns6318:0crwdne6318:0" + }, + "navbar": { + "items": { + "home": "crwdns6320:0crwdne6320:0", + "boards": "crwdns6322:0crwdne6322:0", + "apps": "crwdns6324:0crwdne6324:0", + "integrations": "crwdns6326:0crwdne6326:0", + "searchEngies": "crwdns6328:0crwdne6328:0", + "medias": "crwdns6330:0crwdne6330:0", + "users": { + "label": "crwdns6332:0crwdne6332:0", + "items": { + "manage": "crwdns6334:0crwdne6334:0", + "invites": "crwdns6336:0crwdne6336:0", + "groups": "crwdns6338:0crwdne6338:0" + } + }, + "tools": { + "label": "crwdns6340:0crwdne6340:0", + "items": { + "docker": "crwdns6342:0crwdne6342:0", + "logs": "crwdns6344:0crwdne6344:0", + "api": "crwdns6346:0crwdne6346:0", + "tasks": "crwdns6348:0crwdne6348:0" + } + }, + "settings": "crwdns6350:0crwdne6350:0", + "help": { + "label": "crwdns6352:0crwdne6352:0", + "items": { + "documentation": "crwdns6354:0crwdne6354:0", + "submitIssue": "crwdns6356:0crwdne6356:0", + "discord": "crwdns6358:0crwdne6358:0", + "sourceCode": "crwdns6360:0crwdne6360:0" + } + }, + "about": "crwdns6362:0crwdne6362:0" + } + }, + "page": { + "home": { + "statistic": { + "board": "crwdns6364:0crwdne6364:0", + "user": "crwdns6366:0crwdne6366:0", + "invite": "crwdns6368:0crwdne6368:0", + "integration": "crwdns6370:0crwdne6370:0", + "app": "crwdns6372:0crwdne6372:0", + "group": "crwdns6374:0crwdne6374:0" + }, + "statisticLabel": { + "boards": "crwdns6376:0crwdne6376:0", + "resources": "crwdns6378:0crwdne6378:0", + "authentication": "crwdns6380:0crwdne6380:0", + "authorization": "crwdns6382:0crwdne6382:0" + } + }, + "board": { + "title": "crwdns6384:0crwdne6384:0", + "action": { + "new": { + "label": "crwdns6386:0crwdne6386:0" + }, + "open": { + "label": "crwdns6388:0crwdne6388:0" + }, + "settings": { + "label": "crwdns6390:0crwdne6390:0" + }, + "setHomeBoard": { + "label": "crwdns6392:0crwdne6392:0", + "badge": { + "label": "crwdns6394:0crwdne6394:0", + "tooltip": "crwdns6396:0crwdne6396:0" + } + }, + "delete": { + "label": "crwdns6398:0crwdne6398:0", + "confirm": { + "title": "crwdns6400:0crwdne6400:0", + "description": "crwdns6402:0{name}crwdne6402:0" + } + } + }, + "visibility": { + "public": "crwdns6404:0crwdne6404:0", + "private": "crwdns6406:0crwdne6406:0" + }, + "modal": { + "createBoard": { + "field": { + "name": { + "label": "crwdns6408:0crwdne6408:0" + } + } + } + } + }, + "media": { + "includeFromAllUsers": "crwdns6410:0crwdne6410:0" + }, + "user": { + "back": "crwdns6412:0crwdne6412:0", + "fieldsDisabledExternalProvider": "crwdns6414:0crwdne6414:0", + "setting": { + "general": { + "title": "crwdns6416:0crwdne6416:0", + "item": { + "language": "crwdns6418:0crwdne6418:0", + "board": "crwdns6420:0crwdne6420:0", + "firstDayOfWeek": "crwdns6422:0crwdne6422:0", + "accessibility": "crwdns6424:0crwdne6424:0" + } + }, + "security": { + "title": "crwdns6426:0crwdne6426:0" + }, + "board": { + "title": "crwdns6428:0crwdne6428:0" + } + }, + "list": { + "metaTitle": "crwdns6430:0crwdne6430:0", + "title": "crwdns6432:0crwdne6432:0" + }, + "edit": { + "metaTitle": "crwdns6434:0{username}crwdne6434:0" + }, + "create": { + "metaTitle": "crwdns6436:0crwdne6436:0", + "title": "crwdns6438:0crwdne6438:0", + "step": { + "personalInformation": { + "label": "crwdns6440:0crwdne6440:0" + }, + "security": { + "label": "crwdns6442:0crwdne6442:0" + }, + "groups": { + "label": "crwdns6444:0crwdne6444:0", + "title": "crwdns6446:0crwdne6446:0", + "description": "crwdns6448:0{everyoneGroup}crwdne6448:0" + }, + "review": { + "label": "crwdns6450:0crwdne6450:0" + }, + "completed": { + "title": "crwdns6452:0crwdne6452:0" + }, + "error": { + "title": "crwdns6454:0crwdne6454:0" + } + }, + "action": { + "createAnother": "crwdns6456:0crwdne6456:0", + "back": "crwdns6458:0crwdne6458:0" + } + }, + "invite": { + "title": "crwdns6460:0crwdne6460:0", + "action": { + "new": { + "title": "crwdns6462:0crwdne6462:0", + "description": "crwdns6464:0crwdne6464:0" + }, + "copy": { + "title": "crwdns6466:0crwdne6466:0", + "description": "crwdns6468:0crwdne6468:0", + "link": "crwdns6470:0crwdne6470:0", + "button": "crwdns6472:0crwdne6472:0" + }, + "delete": { + "title": "crwdns6474:0crwdne6474:0", + "description": "crwdns6476:0crwdne6476:0" + } + }, + "field": { + "id": { + "label": "crwdns6478:0crwdne6478:0" + }, + "creator": { + "label": "crwdns6480:0crwdne6480:0" + }, + "expirationDate": { + "label": "crwdns6482:0crwdne6482:0" + }, + "token": { + "label": "crwdns6484:0crwdne6484:0" + } + } + } + }, + "group": { + "back": "crwdns6486:0crwdne6486:0", + "setting": { + "general": { + "title": "crwdns6488:0crwdne6488:0", + "owner": "crwdns6490:0crwdne6490:0", + "ownerOfGroup": "crwdns6492:0crwdne6492:0", + "ownerOfGroupDeleted": "crwdns6494:0crwdne6494:0" + }, + "members": { + "title": "crwdns6496:0crwdne6496:0", + "search": "crwdns6498:0crwdne6498:0", + "notFound": "crwdns6500:0crwdne6500:0" + }, + "permissions": { + "title": "crwdns6502:0crwdne6502:0", + "form": { + "unsavedChanges": "crwdns6504:0crwdne6504:0" + } + } + } + }, + "settings": { + "title": "crwdns6506:0crwdne6506:0", + "notification": { + "success": { + "message": "crwdns6508:0crwdne6508:0" + }, + "error": { + "message": "crwdns6510:0crwdne6510:0" + } + }, + "section": { + "analytics": { + "title": "crwdns6512:0crwdne6512:0", + "general": { + "title": "crwdns6514:0crwdne6514:0", + "text": "crwdns6516:0crwdne6516:0" + }, + "widgetData": { + "title": "crwdns6518:0crwdne6518:0", + "text": "crwdns6520:0crwdne6520:0" + }, + "integrationData": { + "title": "crwdns6522:0crwdne6522:0", + "text": "crwdns6524:0crwdne6524:0" + }, + "usersData": { + "title": "crwdns6526:0crwdne6526:0", + "text": "crwdns6528:0crwdne6528:0" + } + }, + "crawlingAndIndexing": { + "title": "crwdns6530:0crwdne6530:0", + "warning": "crwdns6532:0crwdne6532:0", + "noIndex": { + "title": "crwdns6534:0crwdne6534:0", + "text": "crwdns6536:0crwdne6536:0" + }, + "noFollow": { + "title": "crwdns6538:0crwdne6538:0", + "text": "crwdns6540:0crwdne6540:0" + }, + "noTranslate": { + "title": "crwdns6542:0crwdne6542:0", + "text": "crwdns6544:0crwdne6544:0" + }, + "noSiteLinksSearchBox": { + "title": "crwdns6546:0crwdne6546:0", + "text": "crwdns6548:0crwdne6548:0" + } + }, + "board": { + "title": "crwdns6550:0crwdne6550:0", + "homeBoard": { + "label": "crwdns6552:0crwdne6552:0", + "description": "crwdns6554:0crwdne6554:0" + } + }, + "appearance": { + "title": "crwdns6556:0crwdne6556:0", + "defaultColorScheme": { + "label": "crwdns6558:0crwdne6558:0", + "options": { + "light": "crwdns6560:0crwdne6560:0", + "dark": "crwdns6562:0crwdne6562:0" + } + } + }, + "culture": { + "title": "crwdns6564:0crwdne6564:0", + "defaultLocale": { + "label": "crwdns6566:0crwdne6566:0" + } + } + } + }, + "tool": { + "tasks": { + "title": "crwdns6568:0crwdne6568:0", + "status": { + "idle": "crwdns6570:0crwdne6570:0", + "running": "crwdns6572:0crwdne6572:0", + "error": "crwdns6574:0crwdne6574:0" + }, + "job": { + "iconsUpdater": { + "label": "crwdns6576:0crwdne6576:0" + }, + "analytics": { + "label": "crwdns6578:0crwdne6578:0" + }, + "smartHomeEntityState": { + "label": "crwdns6580:0crwdne6580:0" + }, + "ping": { + "label": "crwdns6582:0crwdne6582:0" + }, + "mediaServer": { + "label": "crwdns6584:0crwdne6584:0" + }, + "mediaOrganizer": { + "label": "crwdns6586:0crwdne6586:0" + }, + "downloads": { + "label": "crwdns6588:0crwdne6588:0" + }, + "mediaRequestStats": { + "label": "crwdns6590:0crwdne6590:0" + }, + "mediaRequestList": { + "label": "crwdns6592:0crwdne6592:0" + }, + "rssFeeds": { + "label": "crwdns6594:0crwdne6594:0" + }, + "indexerManager": { + "label": "crwdns6596:0crwdne6596:0" + }, + "healthMonitoring": { + "label": "crwdns6598:0crwdne6598:0" + }, + "dnsHole": { + "label": "crwdns6600:0crwdne6600:0" + }, + "sessionCleanup": { + "label": "crwdns6602:0crwdne6602:0" + }, + "updateChecker": { + "label": "crwdns6604:0crwdne6604:0" + }, + "mediaTranscoding": { + "label": "crwdns6606:0crwdne6606:0" + } + } + }, + "api": { + "title": "crwdns6608:0crwdne6608:0", + "modal": { + "createApiToken": { + "title": "crwdns6610:0crwdne6610:0", + "description": "crwdns6612:0crwdne6612:0", + "button": "crwdns6614:0crwdne6614:0" + } + }, + "tab": { + "documentation": { + "label": "crwdns6616:0crwdne6616:0" + }, + "apiKey": { + "label": "crwdns6618:0crwdne6618:0", + "title": "crwdns6620:0crwdne6620:0", + "button": { + "createApiToken": "crwdns6622:0crwdne6622:0" + }, + "table": { + "header": { + "id": "crwdns6624:0crwdne6624:0", + "createdBy": "crwdns6626:0crwdne6626:0" + } + } + } + } + } + }, + "about": { + "version": "crwdns6628:0{version}crwdne6628:0", + "text": "crwdns6630:0crwdne6630:0", + "accordion": { + "contributors": { + "title": "crwdns6632:0crwdne6632:0", + "subtitle": "crwdns6634:0{count}crwdne6634:0" + }, + "translators": { + "title": "crwdns6636:0crwdne6636:0", + "subtitle": "crwdns6638:0{count}crwdne6638:0" + }, + "libraries": { + "title": "crwdns6640:0crwdne6640:0", + "subtitle": "crwdns6642:0{count}crwdne6642:0" + } + } + } + } + }, + "docker": { + "title": "crwdns6644:0crwdne6644:0", + "table": { + "updated": "crwdns6646:0{when}crwdne6646:0", + "search": "crwdns6648:0{count}crwdne6648:0", + "selected": "crwdns6650:0{selectCount}crwdnd6650:0{totalCount}crwdne6650:0" + }, + "field": { + "name": { + "label": "crwdns6652:0crwdne6652:0" + }, + "state": { + "label": "crwdns6654:0crwdne6654:0", + "option": { + "created": "crwdns6656:0crwdne6656:0", + "running": "crwdns6658:0crwdne6658:0", + "paused": "crwdns6660:0crwdne6660:0", + "restarting": "crwdns6662:0crwdne6662:0", + "exited": "crwdns6664:0crwdne6664:0", + "removing": "crwdns6666:0crwdne6666:0", + "dead": "crwdns6668:0crwdne6668:0" + } + }, + "containerImage": { + "label": "crwdns6670:0crwdne6670:0" + }, + "ports": { + "label": "crwdns6672:0crwdne6672:0" + } + }, + "action": { + "start": { + "label": "crwdns6674:0crwdne6674:0", + "notification": { + "success": { + "title": "crwdns6676:0crwdne6676:0", + "message": "crwdns6678:0crwdne6678:0" + }, + "error": { + "title": "crwdns6680:0crwdne6680:0", + "message": "crwdns6682:0crwdne6682:0" + } + } + }, + "stop": { + "label": "crwdns6684:0crwdne6684:0", + "notification": { + "success": { + "title": "crwdns6686:0crwdne6686:0", + "message": "crwdns6688:0crwdne6688:0" + }, + "error": { + "title": "crwdns6690:0crwdne6690:0", + "message": "crwdns6692:0crwdne6692:0" + } + } + }, + "restart": { + "label": "crwdns6694:0crwdne6694:0", + "notification": { + "success": { + "title": "crwdns6696:0crwdne6696:0", + "message": "crwdns6698:0crwdne6698:0" + }, + "error": { + "title": "crwdns6700:0crwdne6700:0", + "message": "crwdns6702:0crwdne6702:0" + } + } + }, + "remove": { + "label": "crwdns6704:0crwdne6704:0", + "notification": { + "success": { + "title": "crwdns6706:0crwdne6706:0", + "message": "crwdns6708:0crwdne6708:0" + }, + "error": { + "title": "crwdns6710:0crwdne6710:0", + "message": "crwdns6712:0crwdne6712:0" + } + } + }, + "refresh": { + "label": "crwdns6714:0crwdne6714:0", + "notification": { + "success": { + "title": "crwdns6716:0crwdne6716:0", + "message": "crwdns6718:0crwdne6718:0" + }, + "error": { + "title": "crwdns6720:0crwdne6720:0", + "message": "crwdns6722:0crwdne6722:0" + } + } + } + }, + "error": { + "internalServerError": "crwdns6724:0crwdne6724:0" + } + }, + "permission": { + "title": "crwdns6726:0crwdne6726:0", + "userSelect": { + "title": "crwdns6728:0crwdne6728:0" + }, + "groupSelect": { + "title": "crwdns6730:0crwdne6730:0" + }, + "tab": { + "user": "crwdns6732:0crwdne6732:0", + "group": "crwdns6734:0crwdne6734:0", + "inherited": "crwdns6736:0crwdne6736:0" + }, + "field": { + "user": { + "label": "crwdns6738:0crwdne6738:0" + }, + "group": { + "label": "crwdns6740:0crwdne6740:0" + }, + "permission": { + "label": "crwdns6742:0crwdne6742:0" + } + }, + "action": { + "saveUser": "crwdns6744:0crwdne6744:0", + "saveGroup": "crwdns6746:0crwdne6746:0" + } + }, + "navigationStructure": { + "manage": { + "label": "crwdns6748:0crwdne6748:0", + "boards": { + "label": "crwdns6750:0crwdne6750:0" + }, + "integrations": { + "label": "crwdns6752:0crwdne6752:0", + "edit": { + "label": "crwdns6754:0crwdne6754:0" + }, + "new": { + "label": "crwdns6756:0crwdne6756:0" + } + }, + "search-engines": { + "label": "crwdns6758:0crwdne6758:0", + "new": { + "label": "crwdns6760:0crwdne6760:0" + }, + "edit": { + "label": "crwdns6762:0crwdne6762:0" + } + }, + "medias": { + "label": "crwdns6764:0crwdne6764:0" + }, + "apps": { + "label": "crwdns6766:0crwdne6766:0", + "new": { + "label": "crwdns6768:0crwdne6768:0" + }, + "edit": { + "label": "crwdns6770:0crwdne6770:0" + } + }, + "users": { + "label": "crwdns6772:0crwdne6772:0", + "create": { + "label": "crwdns6774:0crwdne6774:0" + }, + "general": "crwdns6776:0crwdne6776:0", + "security": "crwdns6778:0crwdne6778:0", + "board": "crwdns6780:0crwdne6780:0", + "groups": { + "label": "crwdns6782:0crwdne6782:0" + }, + "invites": { + "label": "crwdns6784:0crwdne6784:0" + } + }, + "tools": { + "label": "crwdns6786:0crwdne6786:0", + "docker": { + "label": "crwdns6788:0crwdne6788:0" + }, + "logs": { + "label": "crwdns6790:0crwdne6790:0" + } + }, + "settings": { + "label": "crwdns6792:0crwdne6792:0" + }, + "about": { + "label": "crwdns6794:0crwdne6794:0" + } + } + }, + "search": { + "placeholder": "crwdns6796:0crwdne6796:0", + "nothingFound": "crwdns6798:0crwdne6798:0", + "error": { + "fetch": "crwdns6800:0crwdne6800:0" + }, + "mode": { + "appIntegrationBoard": { + "help": "crwdns6802:0crwdne6802:0", + "group": { + "app": { + "title": "crwdns6804:0crwdne6804:0", + "children": { + "action": { + "open": { + "label": "crwdns6806:0crwdne6806:0" + }, + "edit": { + "label": "crwdns6808:0crwdne6808:0" + } + }, + "detail": { + "title": "crwdns6810:0crwdne6810:0" + } + } + }, + "board": { + "title": "crwdns6812:0crwdne6812:0", + "children": { + "action": { + "open": { + "label": "crwdns6814:0crwdne6814:0" + }, + "homeBoard": { + "label": "crwdns6816:0crwdne6816:0" + }, + "settings": { + "label": "crwdns6818:0crwdne6818:0" + } + }, + "detail": { + "title": "crwdns6820:0crwdne6820:0" + } + } + }, + "integration": { + "title": "crwdns6822:0crwdne6822:0" + } + } + }, + "command": { + "help": "crwdns6824:0crwdne6824:0", + "group": { + "localCommand": { + "title": "crwdns6826:0crwdne6826:0" + }, + "globalCommand": { + "title": "crwdns6828:0crwdne6828:0", + "option": { + "colorScheme": { + "light": "crwdns6830:0crwdne6830:0", + "dark": "crwdns6832:0crwdne6832:0" + }, + "language": { + "label": "crwdns6834:0crwdne6834:0", + "children": { + "detail": { + "title": "crwdns6836:0crwdne6836:0" + } + } + }, + "newBoard": { + "label": "crwdns6838:0crwdne6838:0" + }, + "importBoard": { + "label": "crwdns6840:0crwdne6840:0" + }, + "newApp": { + "label": "crwdns6842:0crwdne6842:0" + }, + "newIntegration": { + "label": "crwdns6844:0crwdne6844:0", + "children": { + "detail": { + "title": "crwdns6846:0crwdne6846:0" + } + } + }, + "newUser": { + "label": "crwdns6848:0crwdne6848:0" + }, + "newInvite": { + "label": "crwdns6850:0crwdne6850:0" + }, + "newGroup": { + "label": "crwdns6852:0crwdne6852:0" + } + } + } + } + }, + "external": { + "help": "crwdns6854:0crwdne6854:0", + "group": { + "searchEngine": { + "title": "crwdns6856:0crwdne6856:0", + "children": { + "action": { + "search": { + "label": "crwdns6858:0{name}crwdne6858:0" + } + }, + "detail": { + "title": "crwdns6860:0crwdne6860:0" + }, + "searchResults": { + "title": "crwdns6862:0crwdne6862:0" + } + }, + "option": { + "google": { + "name": "crwdns6864:0crwdne6864:0", + "description": "crwdns6866:0crwdne6866:0" + }, + "bing": { + "name": "crwdns6868:0crwdne6868:0", + "description": "crwdns6870:0crwdne6870:0" + }, + "duckduckgo": { + "name": "crwdns6872:0crwdne6872:0", + "description": "crwdns6874:0crwdne6874:0" + }, + "torrent": { + "name": "crwdns6876:0crwdne6876:0", + "description": "crwdns6878:0crwdne6878:0" + }, + "youTube": { + "name": "crwdns6880:0crwdne6880:0", + "description": "crwdns6882:0crwdne6882:0" + } + } + } + } + }, + "help": { + "group": { + "mode": { + "title": "crwdns6884:0crwdne6884:0" + }, + "help": { + "title": "crwdns6886:0crwdne6886:0", + "option": { + "documentation": { + "label": "crwdns6888:0crwdne6888:0" + }, + "submitIssue": { + "label": "crwdns6890:0crwdne6890:0" + }, + "discord": { + "label": "crwdns6892:0crwdne6892:0" + } + } + } + } + }, + "home": { + "group": { + "local": { + "title": "crwdns6894:0crwdne6894:0" + } + } + }, + "page": { + "help": "crwdns6896:0crwdne6896:0", + "group": { + "page": { + "title": "crwdns6898:0crwdne6898:0", + "option": { + "manageHome": { + "label": "crwdns6900:0crwdne6900:0" + }, + "manageBoard": { + "label": "crwdns6902:0crwdne6902:0" + }, + "manageApp": { + "label": "crwdns6904:0crwdne6904:0" + }, + "manageIntegration": { + "label": "crwdns6906:0crwdne6906:0" + }, + "manageSearchEngine": { + "label": "crwdns6908:0crwdne6908:0" + }, + "manageMedia": { + "label": "crwdns6910:0crwdne6910:0" + }, + "manageUser": { + "label": "crwdns6912:0crwdne6912:0" + }, + "manageInvite": { + "label": "crwdns6914:0crwdne6914:0" + }, + "manageGroup": { + "label": "crwdns6916:0crwdne6916:0" + }, + "manageDocker": { + "label": "crwdns6918:0crwdne6918:0" + }, + "manageApi": { + "label": "crwdns6920:0crwdne6920:0" + }, + "manageLog": { + "label": "crwdns6922:0crwdne6922:0" + }, + "manageTask": { + "label": "crwdns6924:0crwdne6924:0" + }, + "manageSettings": { + "label": "crwdns6926:0crwdne6926:0" + }, + "about": { + "label": "crwdns6928:0crwdne6928:0" + }, + "homeBoard": { + "label": "crwdns6930:0crwdne6930:0" + }, + "preferences": { + "label": "crwdns6932:0crwdne6932:0" + } + } + } + } + }, + "userGroup": { + "help": "crwdns6934:0crwdne6934:0", + "group": { + "user": { + "title": "crwdns6936:0crwdne6936:0", + "children": { + "action": { + "detail": { + "label": "crwdns6938:0crwdne6938:0" + } + }, + "detail": { + "title": "crwdns6940:0crwdne6940:0" + } + } + }, + "group": { + "title": "crwdns6942:0crwdne6942:0", + "children": { + "action": { + "detail": { + "label": "crwdns6944:0crwdne6944:0" + }, + "manageMember": { + "label": "crwdns6946:0crwdne6946:0" + }, + "managePermission": { + "label": "crwdns6948:0crwdne6948:0" + } + }, + "detail": { + "title": "crwdns6950:0crwdne6950:0" + } + } + } + } + } + }, + "engine": { + "search": "crwdns6952:0crwdne6952:0", + "field": { + "name": { + "label": "crwdns6954:0crwdne6954:0" + }, + "short": { + "label": "crwdns6956:0crwdne6956:0" + }, + "urlTemplate": { + "label": "crwdns6958:0crwdne6958:0" + }, + "description": { + "label": "crwdns6960:0crwdne6960:0" + } + }, + "page": { + "list": { + "title": "crwdns6962:0crwdne6962:0", + "noResults": { + "title": "crwdns6964:0crwdne6964:0", + "action": "crwdns6966:0crwdne6966:0" + }, + "interactive": "crwdns6968:0crwdne6968:0" + }, + "create": { + "title": "crwdns6970:0crwdne6970:0", + "notification": { + "success": { + "title": "crwdns6972:0crwdne6972:0", + "message": "crwdns6974:0crwdne6974:0" + }, + "error": { + "title": "crwdns6976:0crwdne6976:0", + "message": "crwdns6978:0crwdne6978:0" + } + } + }, + "edit": { + "title": "crwdns6980:0crwdne6980:0", + "notification": { + "success": { + "title": "crwdns6982:0crwdne6982:0", + "message": "crwdns6984:0crwdne6984:0" + }, + "error": { + "title": "crwdns6986:0crwdne6986:0", + "message": "crwdns6988:0crwdne6988:0" + } + }, + "configControl": "crwdns6990:0crwdne6990:0", + "searchEngineType": { + "generic": "crwdns6992:0crwdne6992:0", + "fromIntegration": "crwdns6994:0crwdne6994:0" + } + }, + "delete": { + "title": "crwdns6996:0crwdne6996:0", + "message": "crwdns6998:0{name}crwdne6998:0", + "notification": { + "success": { + "title": "crwdns7000:0crwdne7000:0", + "message": "crwdns7002:0crwdne7002:0" + }, + "error": { + "title": "crwdns7004:0crwdne7004:0", + "message": "crwdns7006:0crwdne7006:0" + } + } + } + } + } + } +} diff --git a/packages/translation/src/lang/cs.json b/packages/translation/src/lang/cs.json index 7f85bfb93..2d0226e13 100644 --- a/packages/translation/src/lang/cs.json +++ b/packages/translation/src/lang/cs.json @@ -1,26 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "Vítejte v Homarru", + "subtitle": "Pojďme začít nastavením instance Homarru.", + "description": "Chcete-li začít, zvolte, jak chcete nastavit instanci Homarru.", + "action": { + "scratch": "Začít od začátku", + "importOldmarr": "Import z Homarru před verzí 1.0" + } + }, + "import": { + "title": "Import dat", + "subtitle": "Můžete importovat data z existující instance Homarru.", + "dropzone": { + "title": "Přetáhněte zip soubor sem nebo klikněte pro procházení souborů", + "description": "Nahraný zip soubor bude zpracován a budete si moci vybrat, co chcete importovat" + }, + "fileInfo": { + "action": { + "change": "Změnit soubor" + } + }, + "importSettings": { + "title": "Importovat nastavení", + "description": "Konfigurovat chování importu" + }, + "boardSelection": { + "title": "Nalezeno {count} ploch", + "description": "Vyberte všechny plochy s velikostmi, které chcete importovat", + "action": { + "selectAll": "Vybrat vše", + "unselectAll": "Zrušit vybraní všeho" + } + }, + "summary": { + "title": "Přehled importu", + "description": "V následujícím přehledu můžete vidět, co bude importováno", + "action": { + "import": "Potvrdit import a pokračovat" + }, + "entities": { + "apps": "Aplikace", + "boards": "Plochy", + "integrations": "Integrace", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "Zadejte token pro import", + "field": { + "token": { + "label": "Token", + "description": "" + } + }, + "notification": { + "error": { + "title": "Neplatný token", + "message": "Token, který jste zadali je neplatný" + } + } + } + }, + "user": { + "title": "Správce", + "subtitle": "Zadejte přihlašovací údaje pro administrátora.", + "notification": { + "success": { + "title": "Uživatel byl vytvořen", + "message": "Uživatel byl úspěšně vytvořen" + }, + "error": { + "title": "Vytvoření uživatele se nezdařilo" + } + } + }, + "group": { + "title": "Externí skupina", + "subtitle": "Zadejte skupinu, která by měla být použita pro externí uživatele.", + "form": { + "name": { + "label": "Název skupiny", + "description": "" + } + } + }, + "settings": { + "title": "Nastavení", + "subtitle": "Konfigurace nastavení serveru." + }, + "finish": { + "title": "Dokončit nastavení", + "subtitle": "Jste připraveni začít!", + "description": "Úspěšně jste dokončili proces nastavení. Nyní můžete začít používat Homarr. Vyberte další akci:", + "action": { + "goToBoard": "Přejít na plochu {name}", + "createBoard": "Vytvořte svou první plochu", + "inviteUser": "Pozvat ostatní uživatele", + "docs": "Přečtěte si dokumentaci" + } + } + }, + "backToStart": "Zpět na začátek" + }, "user": { "title": "Uživatelé", "name": "Uživatel", "page": { "login": { - "title": "", - "subtitle": "" + "title": "Přihlaste se ke svému účtu", + "subtitle": "Vítejte zpět! Zadejte prosím Vaše přihlašovací údaje" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "Připojit se k Homarrovi", + "subtitle": "Vítejte v Homarru! Vytvořte si prosím svůj účet", + "description": "Byli jste pozváni {username}" }, "init": { - "title": "", - "subtitle": "" + "title": "Nová instalace Homarru", + "subtitle": "Vytvořte prosím původního administrátora" } }, "field": { "email": { "label": "E-mail", - "verified": "" + "verified": "Ověřeno" }, "username": { "label": "Uživatelské jméno" @@ -28,46 +133,46 @@ "password": { "label": "Heslo", "requirement": { - "length": "", + "length": "Obsahuje alespoň 8 znaků", "lowercase": "Obsahuje malé písmeno", "uppercase": "Obsahuje velké písmeno", "number": "Obsahuje číslo", - "special": "" + "special": "Obsahuje speciální symbol" } }, "passwordConfirm": { "label": "Potvrďte heslo" }, "previousPassword": { - "label": "" + "label": "Původní heslo" }, "homeBoard": { - "label": "" + "label": "Domovská plocha" }, "pingIconsEnabled": { - "label": "" + "label": "Používat ikony pro pingy" } }, "error": { - "usernameTaken": "" + "usernameTaken": "Uživatelské jméno je již používáno" }, "action": { "login": { "label": "Přihlásit se", - "labelWith": "", + "labelWith": "Přihlaste se pomocí {provider}", "notification": { "success": { - "title": "", - "message": "" + "title": "Přihlášení bylo úspěšné", + "message": "Nyní jste přihlášeni" }, "error": { - "title": "", - "message": "" + "title": "Příhlášení selhalo", + "message": "Vaše přihlášení se nezdařilo" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "Zapomněli jste Vaše heslo?", + "description": "Administrátor může použít následující příkaz k obnovení Vašeho hesla:" } }, "register": { @@ -75,27 +180,37 @@ "notification": { "success": { "title": "Účet byl vytvořen", - "message": "" + "message": "Chcete-li pokračovat, přihlaste se" }, "error": { - "title": "", - "message": "" + "title": "Vytvoření účtu se nezdařilo", + "message": "Váš účet se nepodařilo vytvořit" } } }, "create": "Vytvořit uživatele", "changePassword": { - "label": "", + "label": "Změnit heslo", "notification": { "success": { - "message": "" + "message": "Heslo bylo úspěšně změněno" }, "error": { - "message": "" + "message": "Nepodařilo se změnit heso" } } }, "changeHomeBoard": { + "notification": { + "success": { + "message": "Domovská plocha byla úspěšně změněna" + }, + "error": { + "message": "Nepodařilo se změnit domovskou plochu" + } + } + }, + "changeDefaultSearchEngine": { "notification": { "success": { "message": "" @@ -108,48 +223,48 @@ "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "První den v týdnu byl úspěšně změněn" }, "error": { - "message": "" + "message": "Nelze změnit první den v týdnu" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "Ikony pingu byly úspěšně přepnuty" }, "error": { - "message": "" + "message": "Nelze přepnout ikony pingu" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Změnit obrázek", "notification": { "success": { - "message": "" + "message": "Obrázek byl úspěšně změněn" }, "error": { - "message": "" + "message": "Nepodařilo se změnit obrázek" }, "toLarge": { - "title": "", - "message": "" + "title": "Obrázek je příliš velký", + "message": "Maximální velikost obrázku je {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Odebrat obrázek", + "confirm": "Opravdu chcete odstranit tento obrázek?", "notification": { "success": { - "message": "" + "message": "Obrázek byl úspěšně odstraněn" }, "error": { - "message": "" + "message": "Obrázek nelze odstranit" } } } @@ -157,63 +272,63 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "Profil byl úspěšně aktualizován" }, "error": { - "message": "" + "message": "Profil nelze aktualizovat" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "Trvale smazat uživatele", + "description": "Smaže tohoto uživatele včetně jeho nastavení. Neodstraní žádné plochy. Uživatel nebude upozorněn.", + "confirm": "Jste si jisti, že chcete odstranit uživatele {username} včetně jejich nastavení?" }, "select": { - "label": "", - "notFound": "" + "label": "Vybrat uživatele", + "notFound": "Nebyl nalezen žádný uživatel" }, "transfer": { - "label": "" + "label": "Vyberte nového vlastníka" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "Skupiny", + "name": "Skupina", + "search": "Najít skupinu", "field": { "name": "Název", - "members": "" + "members": "Členové" }, "permission": { "admin": { "title": "Administrátor", "item": { "admin": { - "label": "", - "description": "" + "label": "Administrátor", + "description": "Uživatelé s tímto oprávněním mají plný přístup ke všem funkcím a nastavením" } } }, "app": { - "title": "", + "title": "Aplikace", "item": { "create": { - "label": "", - "description": "" + "label": "Vytvořit aplikace", + "description": "Povolit členům vytvářet aplikace" }, "use-all": { - "label": "", - "description": "" + "label": "Používat všechny aplikace", + "description": "Umožňuje členům přidávat do jejich ploch jakékoli aplikace" }, "modify-all": { - "label": "", - "description": "" + "label": "Upravit všechny aplikace", + "description": "Umožňuje členům upravovat všechny aplikace" }, "full-all": { - "label": "", - "description": "" + "label": "Úplný přístup k aplikacím", + "description": "Umožňuje členům spravovat, používat a mazat jakoukoli aplikaci" } } }, @@ -221,169 +336,170 @@ "title": "Plochy", "item": { "create": { - "label": "", - "description": "" + "label": "Tvorba ploch", + "description": "Umožňuje členům vytvářet plochy" }, "view-all": { - "label": "", - "description": "" + "label": "Zobrazit všechny plochy", + "description": "Umožňuje členům zobrazit všechny plochy" }, "modify-all": { - "label": "", - "description": "" + "label": "Upravit všechny plochy", + "description": "Umožňuje členům upravovat všechny plochy (nezahrnuje kontrolu přístupu a nebezpečnou zónu)" }, "full-all": { - "label": "", - "description": "" + "label": "Úplný přístup k plochám", + "description": "Umožňuje členům zobrazit, upravit a odstranit všechny plochy (včetně kontroly přístupu a nebezpečné zóny)" } } }, "integration": { - "title": "", + "title": "Integrace", "item": { "create": { - "label": "", - "description": "" + "label": "Vytvořit integrace", + "description": "Povolit členům vytvářet integrace" }, "use-all": { - "label": "", - "description": "" + "label": "Použít všechny integrace", + "description": "Umožňuje členům přidávat do jejich ploch jakékoli integrace" }, "interact-all": { - "label": "", - "description": "" + "label": "Interakce s jakoukoli integrací", + "description": "Umožnit členům interagovat s jakoukoli integrací" }, "full-all": { - "label": "", - "description": "" + "label": "Plný přístup k integraci", + "description": "Umožňuje členům spravovat, používat a interagovat s jakoukoli integrací" } } }, "media": { - "title": "", + "title": "Média", "item": { "upload": { - "label": "", - "description": "" + "label": "Nahrávat média", + "description": "Povolit členům nahrávat média" }, "view-all": { - "label": "", - "description": "" + "label": "Zobrazit všechna média", + "description": "Umožňuje členům nahrávat média" }, "full-all": { - "label": "", - "description": "" + "label": "Úplný přístup k médiím", + "description": "Umožňuje členům spravovat a mazat všechny mediální soubory" } } }, "other": { - "title": "", + "title": "Ostatní", "item": { "view-logs": { - "label": "", - "description": "" + "label": "Zobrazit logy", + "description": "Umožňuje členům prohlížet logy" } } }, "search-engine": { - "title": "", + "title": "Vyhledávače", "item": { "create": { - "label": "", - "description": "" + "label": "Vytvořit vyhledávače", + "description": "Umožňuje členům vytvářet vyhledávače" }, "modify-all": { "label": "", - "description": "" + "description": "Umožňuje členům upravovat všechny vyhledávače" }, "full-all": { - "label": "", - "description": "" + "label": "Úplný přístup k vyhledávačům", + "description": "Umožňuje členům spravovat a mazat jakýkoliv vyhledávač" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "Někteří členové jsou od externích poskytovatelů a nelze je spravovat zde", + "external": "Všichni členové jsou od externích poskytovatelů a nelze je spravovat zde" }, "reservedNotice": { - "message": "" + "message": "Tato skupina je vyhrazena pro používání systému a omezuje některé akce. " }, "action": { "create": { - "label": "", + "label": "Nová skupina", "notification": { "success": { - "message": "" + "message": "Skupina byla úspěšně vytvořena" }, "error": { - "message": "" + "message": "Skupinu se nepodařilo vytvořit" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "Převést vlastnictví", + "description": "Převést vlastnictví této skupiny na jiného uživatele.", + "confirm": "Jste si jisti, že chcete převést vlastnictví skupiny {name} na {username}?", "notification": { "success": { "message": "" }, "error": { - "message": "" + "message": "Nelze převést vlastnictví" } } }, "addMember": { - "label": "" + "label": "Přidat člena" }, "removeMember": { - "label": "", - "confirm": "" + "label": "Odebrat člena", + "confirm": "Jste si jisti, že chcete odstranit {user} z této skupiny?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "Vymazat skupinu", + "description": "Jakmile smažete skupinu, není možné se vrátit zpět. Prosím, buďte si jistí.", + "confirm": "Jste si jisti, že chcete odstranit skupinu {name}?", "notification": { "success": { - "message": "" + "message": "Skupina {name} byla úspěšně smazána" }, "error": { - "message": "" + "message": "Nelze odstranit skupinu {name}" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "Oprávnění byla uložena", + "message": "Oprávnění byla úspěšně uložena" }, "error": { - "title": "", - "message": "" + "title": "Oprávnění nebyla uložena", + "message": "Oprávnění nebyla uložena" } } }, "update": { "notification": { "success": { - "message": "" + "message": "Skupina {name} byla úspěšně uložena" }, "error": { - "message": "" + "message": "Nelze uložit skupinu {name}" } } }, "select": { - "label": "", - "notFound": "" + "label": "Vyberte skupinu", + "notFound": "Nebyla nalezena žádná skupina" } } }, "app": { + "search": "", "page": { "list": { "title": "Aplikace", @@ -401,34 +517,34 @@ }, "error": { "title": "", - "message": "" + "message": "Aplikaci nelze vytvořit" } } }, "edit": { - "title": "", + "title": "Upravit aplikaci", "notification": { "success": { - "title": "", - "message": "" + "title": "Změny úspěšně aplikovány", + "message": "Aplikace byla úspěšně uložena" }, "error": { - "title": "", - "message": "" + "title": "Nepodařilo se uložit změny", + "message": "Aplikaci se nepodařilo uložit" } } }, "delete": { - "title": "", - "message": "", + "title": "Vymazat aplikaci", + "message": "Jste si jisti, že chcete vymazat aplikaci {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "Úspěšně odstraněno", + "message": "Aplikace byla úspěšně odstraněna" }, "error": { - "title": "", - "message": "" + "title": "Smazání se nezdařilo", + "message": "Nelze odstranit aplikaci" } } } @@ -438,15 +554,15 @@ "label": "Název" }, "description": { - "label": "" + "label": "Popis" }, "url": { - "label": "" + "label": "Url" } }, "action": { "select": { - "label": "", + "label": "Vybrat aplikaci", "notFound": "" } } @@ -454,49 +570,49 @@ "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "Integrace", + "search": "Prohledat integrace", "noResults": { - "title": "" + "title": "Zatím nejsou žádné integrace" } }, "create": { - "title": "", + "title": "Nová integrace {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "Vytvoření bylo úspěšné", + "message": "Integrace byla úspěšně vytvořena" }, "error": { - "title": "", - "message": "" + "title": "Vytvoření se nezdařilo", + "message": "Integraci se nepodařilo vytvořit" } } }, "edit": { - "title": "", + "title": "Upravit integraci {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "Změny byly úspěšně aplikovány", + "message": "Integrace byla úspěšně uložena" }, "error": { - "title": "", - "message": "" + "title": "Nepodařilo se uložit změny", + "message": "Integraci se nepodařilo uložit" } } }, "delete": { - "title": "", - "message": "", + "title": "Smazat integraci", + "message": "Jste si jisti, že chcete vymazat integraci {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "Odstránění bylo úspěšné", + "message": "Integrace byla úspěšně smazána" }, "error": { - "title": "", - "message": "" + "title": "Smazání se nezdařilo", + "message": "Nepodařilo se odstranit integraci" } } } @@ -506,58 +622,62 @@ "label": "Název" }, "url": { - "label": "" + "label": "Url" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { - "create": "" + "create": "Nová integrace" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "Otestovat připojení a vytvořit", + "edit": "Otestovat připojení a uložit" }, "alertNotice": "", "notification": { "success": { - "title": "", + "title": "Spojení bylo úspěšné", "message": "" }, "invalidUrl": { "title": "Neplatná URL adresa", - "message": "" + "message": "URL adresa je neplatná" }, "secretNotDefined": { - "title": "", - "message": "" + "title": "Chybějící přihlašovací údaje", + "message": "Nebyly poskytnuty všechny přihlašovací údaje" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "Neplatné přihlašovací údaje", + "message": "Přihlašovací údaje jsou neplatné" }, "commonError": { - "title": "", - "message": "" + "title": "Spojení selhalo", + "message": "Spojení nelze navázat" }, "badRequest": { - "title": "", + "title": "Chybný požadavek", "message": "" }, "unauthorized": { "title": "", - "message": "" + "message": "Pravděpodobně špatné přihlašovací údaje" }, "forbidden": { - "title": "", - "message": "" + "title": "Zakázáno", + "message": "Pravděpodobně chybějící oprávnění" }, "notFound": { "title": "", - "message": "" + "message": "Pravděpodobně špatná adresa URL nebo cesta" }, "internalServerError": { - "title": "", - "message": "" + "title": "Interní chyba serveru", + "message": "Server zaznamenal chybu" }, "serviceUnavailable": { "title": "", @@ -569,7 +689,7 @@ }, "domainNotFound": { "title": "", - "message": "" + "message": "Doména nebyla nalezena" }, "connectionRefused": { "title": "", @@ -581,30 +701,34 @@ }, "wrongPath": { "title": "", - "message": "" + "message": "Cesta pravděpodobně není správná" } } }, "secrets": { - "title": "", - "lastUpdated": "", - "secureNotice": "", + "title": "Tajné klíče", + "lastUpdated": "Naposledy aktualizováno {date}", + "notSet": { + "label": "Žádná hodnota není nenastavena", + "tooltip": "Tento požadovaný tajný klíč ještě nebyl nastaven" + }, + "secureNotice": "Tento tajný klíč nelze získat po vytvoření", "reset": { - "title": "", - "message": "" + "title": "Resetovat tajný klíč", + "message": "Jste si jisti, že chcete resetovat tento tajný klíč?" }, "noSecretsRequired": { - "segmentTitle": "", - "text": "" + "segmentTitle": "Žádné tajné klíče", + "text": "Pro tuto integraci nejsou vyžadovány žádné tajné klíče" }, "kind": { "username": { "label": "Uživatelské jméno", - "newLabel": "" + "newLabel": "Nové uživatelské jméno" }, "apiKey": { - "label": "", - "newLabel": "" + "label": "API klíč", + "newLabel": "Nový API klíč" }, "password": { "label": "Heslo", @@ -619,8 +743,8 @@ } }, "media": { - "plural": "", - "search": "", + "plural": "Média", + "search": "Najít mediální soubor", "field": { "name": "Název", "size": "Velikost", @@ -628,119 +752,127 @@ }, "action": { "upload": { - "label": "", - "file": "", + "label": "Nahrát mediální soubor", + "file": "Vybrat soubor", "notification": { "success": { - "message": "" + "message": "Mediální soubor byl úspěšně nahrán" }, "error": { - "message": "" + "message": "Nepodařilo se nahrát mediální soubor" } } }, "delete": { - "label": "", - "description": "", + "label": "Vymazat mediální soubor", + "description": "Jste si jisti, že chcete vymazat mediální soubor ?", "notification": { "success": { - "message": "" + "message": "Mediální soubor byl úspěšně odstraněn" }, "error": { - "message": "" + "message": "Nepodařilo se vymazat mediální soubor" } } }, "copy": { - "label": "" + "label": "Zkopírovat URL" } } }, "common": { - "beta": "", + "beta": "Beta", "error": "Chyba", "action": { "add": "Přidat", "apply": "Použít", - "backToOverview": "", + "backToOverview": "Zpět na přehled", "create": "Vytvořit", "edit": "Upravit", - "import": "", + "import": "Importovat", "insert": "Vložit", "remove": "Odstranit", "save": "Uložit", "saveChanges": "Uložit změny", "cancel": "Zrušit", "delete": "Odstranit", - "discard": "", + "discard": "Zahodit", "confirm": "Potvrdit", - "continue": "", + "continue": "Pokračovat", "previous": "Zpět", "next": "Další", - "checkoutDocs": "", + "checkoutDocs": "Přečtěte si dokumentaci", + "checkLogs": "Pro více podrobností zkontrolujte logy", "tryAgain": "Zkusit znovu", - "loading": "" + "loading": "Načítání" }, - "here": "", + "here": "zde", "iconPicker": { - "label": "", + "label": "URL ikony", "header": "" }, + "colorScheme": { + "options": { + "light": "Světlý", + "dark": "Tmavý" + } + }, "information": { - "min": "", - "max": "", - "days": "", + "min": "Min", + "max": "Max", + "days": "Dnů", "hours": "Hodin", "minutes": "Minut" }, "notification": { "create": { - "success": "", - "error": "" + "success": "Vytvoření bylo úspěšné", + "error": "Vytvoření se nezdařilo" }, "delete": { - "success": "", - "error": "" + "success": "Odstranění bylo úspěšné", + "error": "Odstranění se nezdařilo" }, "update": { - "success": "", - "error": "" + "success": "Změny byly úspěšně aplikovány", + "error": "Nepodařilo se uložit změny" }, "transfer": { - "success": "", - "error": "" + "success": "Přenos úspěšný", + "error": "Přenos se nezdařil" } }, "multiSelect": { "placeholder": "" }, "multiText": { - "placeholder": "", - "addLabel": "" + "placeholder": "Přidat více hodnot", + "addLabel": "Přidat {value}" }, "select": { - "placeholder": "", + "placeholder": "Vybrat hodnotu", "badge": { - "recommended": "" + "recommended": "Doporučeno" } }, "userAvatar": { "menu": { - "switchToDarkMode": "", - "switchToLightMode": "", - "management": "", + "switchToDarkMode": "Přepnout do tmavého režimu", + "switchToLightMode": "Přepnout do světlého režimu", + "management": "Správa", "preferences": "Vaše předvolby", - "logout": "", + "logout": "Odhlásit se", "login": "Přihlásit se", - "homeBoard": "", - "loggedOut": "" + "homeBoard": "Vaše domácí plocha", + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Nebezpečná zóna", "noResults": "Nebyly nalezeny žádné výsledky", "preview": { - "show": "", - "hide": "" + "show": "Zobrazit náhled", + "hide": "Skrýt náhled" }, "zod": { "errors": { @@ -750,7 +882,7 @@ "startsWith": "Toto pole musí začínat {startsWith}", "endsWith": "Toto pole musí končit {endsWith}", "includes": "Toto pole musí obsahovat {includes}", - "invalidEmail": "" + "invalidEmail": "Toto pole musí být platný e-mail" }, "tooSmall": { "string": "Toto pole musí obsahovat alespoň {minimum} znaků", @@ -761,12 +893,14 @@ "number": "Toto pole musí být menší nebo rovno {maximum}" }, "custom": { - "passwordsDoNotMatch": "", - "passwordRequirements": "", - "boardAlreadyExists": "", - "invalidFileType": "", - "fileTooLarge": "", - "invalidConfiguration": "" + "passwordsDoNotMatch": "Hesla se neshodují", + "passwordRequirements": "Heslo nesplňuje požadavky", + "boardAlreadyExists": "Plocha s tímto názvem již existuje", + "invalidFileType": "Neplatný typ souboru, očekáván {expected}", + "invalidFileName": "", + "fileTooLarge": "Soubor je příliš velký, maximální velikost je {maxSize}", + "invalidConfiguration": "Neplatná konfigurace", + "groupNameTaken": "Název skupiny je již používán" } } } @@ -774,12 +908,12 @@ "section": { "dynamic": { "action": { - "create": "", - "remove": "" + "create": "Nová dynamická sekce", + "remove": "Odstranit dynamickou sekci" }, "remove": { - "title": "", - "message": "" + "title": "Odstranit dynamickou sekci", + "message": "Jste si jisti, že chcete odstranit tuto dynamickou sekci? Položky budou přesunuty na stejné místo v nadřazené sekci." } }, "category": { @@ -789,29 +923,29 @@ } }, "action": { - "create": "", - "edit": "", - "remove": "", + "create": "Nová kategorie", + "edit": "Přejmenovat kategorii", + "remove": "Odstranit kategorii", "moveUp": "Posunout nahoru", "moveDown": "Posunout dolů", - "createAbove": "", - "createBelow": "" + "createAbove": "Nová kategorie nad", + "createBelow": "Nová kategorie pod" }, "create": { - "title": "", - "submit": "" + "title": "Nová kategorie", + "submit": "Přidat kategorii" }, "remove": { - "title": "", - "message": "" + "title": "Odstranit kategorii", + "message": "Jste si jisti, že chcete odstranit kategorii {name}?" }, "edit": { - "title": "", - "submit": "" + "title": "Přejmenovat kategorii", + "submit": "Přejmenovat kategorii" }, "menu": { "label": { - "create": "", + "create": "Nová kategorie", "changePosition": "Změnit pozici" } } @@ -821,10 +955,10 @@ "action": { "create": "", "import": "", - "edit": "", - "moveResize": "", - "duplicate": "", - "remove": "" + "edit": "Upravit položku", + "moveResize": "Přesunout / změnit velikost položky", + "duplicate": "Duplikovat položku", + "remove": "Odstranit položku" }, "menu": { "label": { @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -855,7 +990,7 @@ "edit": { "title": "", "advancedOptions": { - "label": "", + "label": "Pokročilé možnosti", "title": "" }, "field": { @@ -869,7 +1004,7 @@ }, "remove": { "title": "", - "message": "" + "message": "Jste si jisti, že chcete tuto položku odstranit?" } }, "widget": { @@ -908,13 +1043,13 @@ "label": "" }, "layout": { - "label": "", + "label": "Rozložení", "option": { "row": { - "label": "" + "label": "Horizontální" }, "column": { - "label": "" + "label": "Vertikální" }, "grid": { "label": "" @@ -929,7 +1064,7 @@ }, "dnsHoleSummary": { "name": "", - "description": "", + "description": "Zobrazí shrnutí vaší DNS Hole", "option": { "layout": { "label": "Rozložení", @@ -941,16 +1076,16 @@ "label": "Vertikální" }, "grid": { - "label": "" + "label": "Mřížka" } } }, "usePiHoleColors": { - "label": "" + "label": "Používat barvy Pi-Hole" } }, "error": { - "internalServerError": "", + "internalServerError": "Nepodařilo se načíst souhrn DNS Hole", "integrationsDisconnected": "" }, "data": { @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Zablokováno dnes", "dnsQueriesToday": "Dotazů dnes", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -974,7 +1110,7 @@ "label": "Vertikální" }, "grid": { - "label": "" + "label": "Mřížka" } } }, @@ -986,21 +1122,21 @@ "internalServerError": "" }, "controls": { - "enableAll": "", - "disableAll": "", - "setTimer": "", + "enableAll": "Povolit vše", + "disableAll": "Zakázat vše", + "setTimer": "Nastavit časovač", "set": "Nastavit", "enabled": "Zapnuto", "disabled": "Vypnuto", - "processing": "", + "processing": "Zpracovávání", "disconnected": "", "hours": "Hodin", "minutes": "Minut", - "unlimited": "" + "unlimited": "Ponechte prázdné pro neomezené" } }, "clock": { - "name": "", + "name": "Datum a čas", "description": "Zobrazuje aktuální datum a čas.", "option": { "customTitleToggle": { @@ -1008,17 +1144,17 @@ "description": "" }, "customTitle": { - "label": "" + "label": "Název" }, "is24HourFormat": { - "label": "", - "description": "" + "label": "24hodinový formát", + "description": "Použít 24hodinový formát místo 12hodinového formátu" }, "showSeconds": { - "label": "" + "label": "Zobrazit vteřiny" }, "useCustomTimezone": { - "label": "" + "label": "Použít pevné časové pásmo" }, "timezone": { "label": "Časové pásmo", @@ -1028,11 +1164,30 @@ "label": "" }, "dateFormat": { - "label": "", + "label": "Formát data", "description": "" } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Zápisník", "description": "", @@ -1095,11 +1250,11 @@ } }, "iframe": { - "name": "", + "name": "iFrame", "description": "Vložte jakýkoli obsah z internetu. Některé webové stránky mohou omezit přístup.", "option": { "embedUrl": { - "label": "" + "label": "Embed URL" }, "allowFullScreen": { "label": "Povolit celou obrazovku" @@ -1127,12 +1282,13 @@ } }, "error": { - "noUrl": "", + "noUrl": "Nebyla zadána URL adresa iFrame", + "unsupportedProtocol": "", "noBrowerSupport": "Váš prohlížeč nepodporuje iFrame. Aktualizujte, prosím, svůj prohlížeč." } }, "smartHome-entityState": { - "name": "", + "name": "Stav entity", "description": "", "option": { "entityId": { @@ -1171,7 +1327,7 @@ "releaseType": { "label": "Typ vydání filmu pro Radarr", "options": { - "inCinemas": "", + "inCinemas": "V kinech", "digitalRelease": "", "physicalRelease": "" } @@ -1189,24 +1345,24 @@ "description": "Zobrazuje aktuální informace o počasí na nastaveném místě.", "option": { "isFormatFahrenheit": { - "label": "" + "label": "Teplota ve Fahrenheitech" }, "location": { "label": "Lokalita pro počasí" }, "showCity": { - "label": "" + "label": "Zobrazit město" }, "hasForecast": { - "label": "" + "label": "Zobrazit předpověď" }, "forecastDayCount": { "label": "", - "description": "" + "description": "Když widget není dostatečně široký, zobrazí se méně dní" }, "dateFormat": { - "label": "", - "description": "" + "label": "Formát data", + "description": "Jak by datum mělo vypadat" } }, "kind": { @@ -1228,16 +1384,16 @@ }, "indexerManager": { "name": "Stav správce indexeru", - "description": "", + "description": "Stav Vašich indexerů", "option": { "openIndexerSiteInNewTab": { - "label": "" + "label": "Otevřít stránku indexeru v nové kartě" } }, "title": "Správce indexeru", "testAll": "Otestovat vše", "error": { - "internalServerError": "" + "internalServerError": "Nepodařilo se načíst stav indexerů" } }, "healthMonitoring": { @@ -1282,14 +1438,14 @@ "latitude": "", "longitude": "", "disabledTooltip": "", - "unknownLocation": "", + "unknownLocation": "Neznámá poloha", "search": "Vyhledat", "table": { "header": { - "city": "", - "country": "", - "coordinates": "", - "population": "" + "city": "Město", + "country": "Státy", + "coordinates": "Souřadnice", + "population": "Populace" }, "action": { "select": "" @@ -1300,19 +1456,16 @@ } }, "integration": { - "noData": "", - "description": "" + "noData": "Nebyla nalezena žádná integrace", + "description": "Klikněte na pro vytvoření nové integrace" }, "app": { "noData": "", - "description": "" + "description": "Klikněte na pro vytvoření nové aplikace" }, "error": { - "action": { - "logs": "" - }, - "noIntegration": "", - "noData": "" + "noIntegration": "Nebyla vybrána žádná integrace", + "noData": "Nejsou k dispozici žádná data o integraci" }, "option": {} }, @@ -1325,7 +1478,7 @@ }, "hasAutoPlay": { "label": "Automatické přehrávání", - "description": "" + "description": "Automatické přehrávání funguje pouze když je ztlumeno kvůli omezením prohlížeče" }, "isMuted": { "label": "" @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "Uživatel", + "name": "Jméno", + "id": "Id" + } }, "downloads": { "name": "", @@ -1370,7 +1528,7 @@ "label": "" }, "categoryFilter": { - "label": "" + "label": "Kategorie/štítky k filtrování" }, "filterIsWhitelist": { "label": "" @@ -1392,19 +1550,19 @@ "detailsTitle": "Datum přidání" }, "category": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Doplňky", + "detailsTitle": "Kategorie (nebo další informace)" }, "downSpeed": { "columnTitle": "Stahování", "detailsTitle": "Rychlost stahování" }, "index": { - "columnTitle": "", + "columnTitle": "#", "detailsTitle": "" }, "id": { - "columnTitle": "" + "columnTitle": "Id" }, "integration": { "columnTitle": "Integrace" @@ -1421,12 +1579,12 @@ "detailsTitle": "" }, "received": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Celkem staženo", + "detailsTitle": "Celkem staženo" }, "sent": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Celkem nahráno", + "detailsTitle": "Celkem nahráno" }, "size": { "columnTitle": "", @@ -1476,7 +1634,7 @@ "resume": "", "delete": { "title": "", - "modalTitle": "", + "modalTitle": "Jsou si jisti, že chcete smazat tento úkol?", "entry": "", "entryAndFiles": "" } @@ -1524,7 +1682,66 @@ }, "users": { "main": "Top uživatelé", - "requests": "" + "requests": "Žádosti" + } + } + }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "Výchozí zobrazení" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "Stroje", + "queue": "Fronta", + "statistics": "Statistiky" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "Ve frontě", + "status": { + "healthy": "V pořádku", + "unhealthy": "Nastal problém" + } + }, + "panel": { + "statistics": { + "empty": "Prázdné", + "transcodes": "Překódování", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "Kodeky", + "videoContainers": "Kontejnery", + "videoResolutions": "Rozlišení" + }, + "workers": { + "empty": "Prázdné", + "table": { + "file": "Soubor", + "eta": "Odhadovaný čas", + "progress": "Postup", + "transcode": "Překódovat", + "healthCheck": "" + } + }, + "queue": { + "empty": "Prázdné", + "table": { + "file": "Soubor", + "size": "Velikost", + "transcode": "Překódovat", + "healthCheck": "" + } } } }, @@ -1558,7 +1775,9 @@ }, "board": { "action": { - "edit": { + "duplicate": { + "title": "", + "message": "", "notification": { "success": { "title": "", @@ -1568,10 +1787,22 @@ "title": "", "message": "" } + } + }, + "edit": { + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "Nelze uložit změny", + "message": "Plochu se nepodařilo uložit" + } }, "confirmLeave": { "title": "", - "message": "" + "message": "Máte neuložené změny, jste si jistí, že chcete odejít?" } }, "oldImport": { @@ -1583,7 +1814,7 @@ }, "error": { "title": "", - "message": "" + "message": "Plochu se nepodařilo importovat, zkontrolujte logy pro více informací" } }, "form": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Malé", "md": "Střední", @@ -1632,19 +1864,19 @@ }, "field": { "pageTitle": { - "label": "" + "label": "Nadpis strany" }, "metaTitle": { "label": "" }, "logoImageUrl": { - "label": "" + "label": "URL adresa loga" }, "faviconImageUrl": { - "label": "" + "label": "URL obrázku Favicon" }, "backgroundImageUrl": { - "label": "" + "label": "Adresa URL obrázku na pozadí" }, "backgroundImageAttachment": { "label": "Příloha obrázku na pozadí", @@ -1663,8 +1895,8 @@ "label": "", "option": { "repeat": { - "label": "", - "description": "" + "label": "Opakovat", + "description": "Obrázek se opakuje tak často, jak je potřeba, aby pokryl celou oblast obrazu na pozadí." }, "no-repeat": { "label": "", @@ -1754,7 +1986,7 @@ "label": "" }, "full": { - "label": "" + "label": "Plný přístup" } } } @@ -1783,11 +2015,11 @@ "confirm": { "public": { "title": "", - "description": "" + "description": "Jste si jisti, že chcete tuto plochu učinit soukromou? Toto skryje tuto plochu před veřejností. Odkazy pro hosty přestanou fungovat." }, "private": { "title": "", - "description": "" + "description": "Jste si jisti, že chcete tuto plochu učinit veřejnou? Toto plochu zpřístupní všem." } } }, @@ -1797,24 +2029,56 @@ "button": "", "confirm": { "title": "Odstranit plochu", - "description": "" + "description": "Jste si jisti, že chcete odstranit tuto plochu? Toto trvale odstraní plochu a veškerý její obsah." } } } } } + }, + "error": { + "noBoard": { + "title": "Vítejte v Homarru", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "Chcete-li tuto stránku schovat pro všechny uživatele, nastavte domovskou plochu pro server" + }, + "user": { + "description": "Zatím jste nenastavili domovskou plochu.", + "link": "Nastavit Vaší domovskou plochu", + "notice": "Chcete-li tuto stránku schovat, nastavte si domovskou plochu ve vašich preferencích" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { "metaTitle": "", "title": { - "morning": "", - "afternoon": "", - "evening": "" + "morning": "Dobré ráno, {username}", + "afternoon": "Dobré odpoledne, {username}", + "evening": "Dobrý večer, {username}" }, "notFound": { "title": "", - "text": "" + "text": "Nepodařilo se nalézt požadovaný zdroj" }, "navbar": { "items": { @@ -1829,7 +2093,7 @@ "items": { "manage": "Spravovat", "invites": "Pozvánky", - "groups": "" + "groups": "Skupiny" } }, "tools": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1862,7 +2127,7 @@ "invite": "Pozvánky", "integration": "", "app": "Aplikace", - "group": "" + "group": "Skupiny" }, "statisticLabel": { "boards": "Plochy", @@ -1890,11 +2155,21 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Trvale smazat", "confirm": { "title": "Odstranit plochu", - "description": "" + "description": "Jste si jisti, že chcete vymazat plochu {name}?" } } }, @@ -1916,14 +2191,21 @@ "includeFromAllUsers": "" }, "user": { - "back": "", - "fieldsDisabledExternalProvider": "", + "back": "Zpět na uživatele", + "fieldsDisabledExternalProvider": "Některá pole jsou vypnuta, protože jsou spravována externím poskytovatelem ověřování.", "setting": { "general": { "title": "Obecné", "item": { - "language": "", - "board": "", + "language": "Jazyk & oblast", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "Výchozí vyhledávač", "firstDayOfWeek": "První den v týdnu", "accessibility": "Přístupnost" } @@ -1940,59 +2222,59 @@ "title": "Uživatelé" }, "edit": { - "metaTitle": "" + "metaTitle": "Upravit uživatele {username}" }, "create": { "metaTitle": "Vytvořit uživatele", - "title": "", + "title": "Vytvořit nového uživatele", "step": { "personalInformation": { - "label": "" + "label": "Osobní údaje" }, "security": { "label": "Bezpečnost" }, "groups": { - "label": "", - "title": "", - "description": "" + "label": "Skupiny", + "title": "Vyberte všechny skupiny, jejichž členem by měl uživatel být", + "description": "Skupina {everyoneGroup} je přiřazena všem uživatelům a nemůže být odstraněna." }, "review": { "label": "" }, "completed": { - "title": "" + "title": "Uživatel byl vytvořen" }, "error": { - "title": "" + "title": "Vytvoření uživatele se nezdařilo" } }, "action": { - "createAnother": "", - "back": "" + "createAnother": "Vytvořit nového uživatele", + "back": "Zpět na seznam uživatelů" } }, "invite": { "title": "Správa pozvánek uživatelů", "action": { "new": { - "title": "", + "title": "Nová pozvánka", "description": "Po vypršení platnosti pozvánka přestane být platná a příjemce pozvánky si nebude moci vytvořit účet." }, "copy": { - "title": "", - "description": "", + "title": "Zkopírovat pozvánku", + "description": "Vaše pozvánka byla vygenerována. Po zavření tohoto okna již nebude možné tento odkaz zkopírovat. Pokud si již nepřejete uvedenou osobu pozvat, můžete tuto pozvánku kdykoli smazat.", "link": "Odkaz na pozvánku", - "button": "" + "button": "Zkopírovat a zavřít" }, "delete": { "title": "Odstranit pozvánku", - "description": "Jste si jisti, že chcete tuto pozvánku smazat? Uživatelé s tímto odkazem již nebudou moci pomocí tohoto odkazu vytvořit účet." + "description": "Jste si jisti, že chcete tuto pozvánku smazat? Uživatelé s tímto odkazem si již nebudou moci pomocí tohoto odkazu vytvořit účet." } }, "field": { "id": { - "label": "" + "label": "ID" }, "creator": { "label": "Vytvořil/a" @@ -2001,29 +2283,29 @@ "label": "Datum konce platnosti" }, "token": { - "label": "" + "label": "Token" } } } }, "group": { - "back": "", + "back": "Zpět na skupiny", "setting": { "general": { "title": "Obecné", - "owner": "", - "ownerOfGroup": "", - "ownerOfGroupDeleted": "" + "owner": "Vlastník", + "ownerOfGroup": "Vlastník této skupiny", + "ownerOfGroupDeleted": "Vlastník této skupiny byl odstraněn. V současné době nemá žádného vlastníka." }, "members": { - "title": "", - "search": "", - "notFound": "" + "title": "Členové", + "search": "Najít člena", + "notFound": "Žádný člen nebyl nenalezen" }, "permissions": { - "title": "", + "title": "Oprávnění", "form": { - "unsavedChanges": "" + "unsavedChanges": "Máte neuložené změny!" } } } @@ -2054,7 +2336,7 @@ "text": "" }, "usersData": { - "title": "", + "title": "Uživatelská data", "text": "" } }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Plochy", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Vzhled", "defaultColorScheme": { "label": "", "options": { @@ -2098,7 +2388,7 @@ "culture": { "title": "", "defaultLocale": { - "label": "" + "label": "Výchozí jazyk" } } } @@ -2112,6 +2402,9 @@ "error": "Chyba" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2143,7 +2436,7 @@ "label": "" }, "indexerManager": { - "label": "" + "label": "Správce indexeru" }, "healthMonitoring": { "label": "" @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2187,15 +2486,15 @@ }, "about": { "version": "", - "text": "", + "text": "Homarr je komunitou řízený open source projekt, který je udržován dobrovolníky. Díky těmto lidem je Homarr od roku 2021 neustále rostoucím projektem. Náš tým na Homarru pracuje zcela na dálku z mnoha různých zemí ve svém volném čase bez jakékoli kompenzace.", "accordion": { "contributors": { - "title": "", - "subtitle": "" + "title": "Přispěvatelé", + "subtitle": "{count} udržuje kód & Homarr" }, "translators": { - "title": "", - "subtitle": "" + "title": "Překladatelé", + "subtitle": "{count} přispívá překladem do mnoha jazyků" }, "libraries": { "title": "", @@ -2245,7 +2544,7 @@ }, "error": { "title": "", - "message": "" + "message": "Nepodařilo se spustit kontejnery" } } }, @@ -2258,7 +2557,7 @@ }, "error": { "title": "", - "message": "" + "message": "Nepodařilo se zastavit kontejnery" } } }, @@ -2271,7 +2570,7 @@ }, "error": { "title": "", - "message": "" + "message": "Nepodařilo se restartovat kontejnery" } } }, @@ -2284,7 +2583,7 @@ }, "error": { "title": "", - "message": "" + "message": "Nepodařilo se odstranit kontejnery" } } }, @@ -2300,36 +2599,55 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { - "title": "", + "title": "Oprávnění", "userSelect": { - "title": "" + "title": "Přidat oprávnění uživatele" }, "groupSelect": { - "title": "" + "title": "Přidat oprávnění ke skupině" }, "tab": { "user": "Uživatelé", - "group": "", - "inherited": "" + "group": "Skupiny", + "inherited": "Zděděné skupiny" }, "field": { "user": { "label": "Uživatel" }, "group": { - "label": "" + "label": "Skupina" }, "permission": { - "label": "" + "label": "Oprávnění" } }, "action": { - "saveUser": "", - "saveGroup": "" + "saveUser": "Uložit oprávnění uživatele", + "saveGroup": "Uložit oprávnění skupiny" } }, "navigationStructure": { @@ -2377,7 +2695,7 @@ "security": "Bezpečnost", "board": "Plochy", "groups": { - "label": "" + "label": "Skupiny" }, "invites": { "label": "Pozvánky" @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2464,15 +2788,15 @@ "dark": "" }, "language": { - "label": "", + "label": "Změnit jazyk", "children": { "detail": { - "title": "" + "title": "Vyberte si preferovaný jazyk" } } }, "newBoard": { - "label": "" + "label": "Vytvořit novou plochu" }, "importBoard": { "label": "" @@ -2489,7 +2813,7 @@ } }, "newUser": { - "label": "" + "label": "Vytvořit nového uživatele" }, "newInvite": { "label": "" @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2634,37 +2981,37 @@ } }, "userGroup": { - "help": "", + "help": "Hledat uživatele nebo skupiny", "group": { "user": { "title": "Uživatelé", "children": { "action": { "detail": { - "label": "" + "label": "Zobrazit detaily uživatele" } }, "detail": { - "title": "" + "title": "Vyberte akci pro uživatele" } } }, "group": { - "title": "", + "title": "Skupiny", "children": { "action": { "detail": { - "label": "" + "label": "Zobrazit detaily skupiny" }, "manageMember": { - "label": "" + "label": "Spravovat členy" }, "managePermission": { - "label": "" + "label": "Spravovat oprávnění" } }, "detail": { - "title": "" + "title": "Vyberte akci pro uživatele" } } } @@ -2705,7 +3052,7 @@ }, "error": { "title": "", - "message": "" + "message": "Nepodařilo se vytvořit vyhledávač" } } }, @@ -2717,8 +3064,8 @@ "message": "" }, "error": { - "title": "", - "message": "" + "title": "Nelze uložit změny", + "message": "Nepodařilo se uložit vyhledávač" } }, "configControl": "", @@ -2729,7 +3076,7 @@ }, "delete": { "title": "", - "message": "", + "message": "Jste si jisti, že chcete odstranit vyhledávač '{name}'?", "notification": { "success": { "title": "", @@ -2737,10 +3084,67 @@ }, "error": { "title": "", - "message": "" + "message": "Nepodařilo se odstranit vyhledávač" } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/da.json b/packages/translation/src/lang/da.json index ae4c57afb..fd6681fca 100644 --- a/packages/translation/src/lang/da.json +++ b/packages/translation/src/lang/da.json @@ -1,26 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "Velkommen til Homarr", + "subtitle": "Lad os komme i gang med at konfigurere din Homarr instans.", + "description": "For at komme i gang, skal du vælge, hvordan du vil konfigurere din Homarr instans.", + "action": { + "scratch": "Start fra bunden", + "importOldmarr": "Importer fra Homarr før 1.0" + } + }, + "import": { + "title": "Importer data", + "subtitle": "Du kan importere data fra en eksisterende Homarr instans.", + "dropzone": { + "title": "Træk zip-filen her eller klik for at gennemse", + "description": "Den uploadede zip vil blive behandlet, og du vil kunne vælge, hvad du vil importere" + }, + "fileInfo": { + "action": { + "change": "Ændre fil" + } + }, + "importSettings": { + "title": "Importer indstillinger", + "description": "Konfigurer importadfærden" + }, + "boardSelection": { + "title": "Fundet {count} tavler", + "description": "Vælg alle tavler med deres størrelser du vil importere", + "action": { + "selectAll": "Vælg alle", + "unselectAll": "Fravælg alle" + } + }, + "summary": { + "title": "Importér sammendrag", + "description": "I nedenstående oversigt kan du se hvad der vil blive importeret", + "action": { + "import": "Bekræft import og fortsæt" + }, + "entities": { + "apps": "Apps", + "boards": "Tavler", + "integrations": "Integrationer", + "credentialUsers": "Brugere, der er legitimerede" + } + }, + "tokenModal": { + "title": "Angiv import token", + "field": { + "token": { + "label": "Token", + "description": "Indtast den viste import token fra din tidligere homarr instans" + } + }, + "notification": { + "error": { + "title": "Ugyldig token", + "message": "Den indtastede token er ugyldig" + } + } + } + }, + "user": { + "title": "Admin bruger", + "subtitle": "Angiv legitimationsoplysninger for din administrator bruger.", + "notification": { + "success": { + "title": "Bruger oprettet", + "message": "Brugeren blev oprettet" + }, + "error": { + "title": "Brugeroprettelse mislykkedes" + } + } + }, + "group": { + "title": "Ekstern gruppe", + "subtitle": "Angiv den gruppe, der skal bruges til eksterne brugere.", + "form": { + "name": { + "label": "Gruppenavn", + "description": "Navn skal matche admin gruppe fra ekstern udbyder" + } + } + }, + "settings": { + "title": "Indstillinger", + "subtitle": "Konfigurer serverindstillinger." + }, + "finish": { + "title": "Afslut opsætningen", + "subtitle": "Du er klar!", + "description": "Du har fuldført opsætningsprocessen. Du kan nu begynde at bruge Homarr. Vælg din næste handling:", + "action": { + "goToBoard": "Gå til {name} tavle", + "createBoard": "Opret din første tavle", + "inviteUser": "Inviter andre brugere", + "docs": "Læs dokumentationen" + } + } + }, + "backToStart": "Tilbage til start" + }, "user": { "title": "Brugere", "name": "Bruger", "page": { "login": { - "title": "", - "subtitle": "" + "title": "Log ind på din konto", + "subtitle": "Velkommen tilbage! Indtast venligst dine legitimationsoplysninger" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "Tilmeld Homarr", + "subtitle": "Velkommen til Homarr! Opret venligst din konto", + "description": "Du blev inviteret af {username}" }, "init": { - "title": "", - "subtitle": "" + "title": "Ny Homarr installation", + "subtitle": "Opret venligst den første administrator bruger" } }, "field": { "email": { "label": "E-mail", - "verified": "" + "verified": "Verificeret" }, "username": { "label": "Brugernavn" @@ -28,46 +133,46 @@ "password": { "label": "Adgangskode", "requirement": { - "length": "", + "length": "Inkluderer mindst 8 tegn", "lowercase": "Inkluderer små bogstaver", "uppercase": "Inkluderer store bogstaver", "number": "Inkluderer nummer", - "special": "" + "special": "Inkluderer specielt symbol" } }, "passwordConfirm": { "label": "Bekræft kodeord" }, "previousPassword": { - "label": "" + "label": "Tidligere adgangskode" }, "homeBoard": { - "label": "" + "label": "Hjemme tavle" }, "pingIconsEnabled": { - "label": "" + "label": "Brug ikoner til pings" } }, "error": { - "usernameTaken": "" + "usernameTaken": "Brugernavn allerede taget" }, "action": { "login": { "label": "Log ind", - "labelWith": "", + "labelWith": "Log ind med {provider}", "notification": { "success": { - "title": "", - "message": "" + "title": "Login lykkedes", + "message": "Du er nu logget ind" }, "error": { - "title": "", - "message": "" + "title": "Login mislykkedes", + "message": "Dit login mislykkedes" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "Glemt din adgangskode?", + "description": "En administrator kan bruge følgende kommando til at nulstille din adgangskode:" } }, "register": { @@ -75,27 +180,37 @@ "notification": { "success": { "title": "Konto oprettet", - "message": "" + "message": "Log venligst på for at fortsætte" }, "error": { - "title": "", - "message": "" + "title": "Oprettelse af konto mislykkedes", + "message": "Din konto kunne ikke oprettes" } } }, "create": "Opret bruger", "changePassword": { - "label": "", + "label": "Skift adgangskode", "notification": { "success": { - "message": "" + "message": "Adgangskoden er blevet ændret" }, "error": { - "message": "" + "message": "Adgangskoden kunne ikke ændres" } } }, "changeHomeBoard": { + "notification": { + "success": { + "message": "Hjemmetavle blev ændret" + }, + "error": { + "message": "Kan ikke ændre hjemmetavle" + } + } + }, + "changeDefaultSearchEngine": { "notification": { "success": { "message": "" @@ -108,48 +223,48 @@ "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "Første ugedag ændret med succes" }, "error": { - "message": "" + "message": "Kan ikke ændre den første ugedag" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "Ping ikoner skiftet" }, "error": { - "message": "" + "message": "Kan ikke skifte ping-ikoner" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Skift billede", "notification": { "success": { - "message": "" + "message": "Billedet blev ændret" }, "error": { - "message": "" + "message": "Kan ikke ændre billede" }, "toLarge": { - "title": "", - "message": "" + "title": "Billedet er for stort", + "message": "Maks billedstørrelse er {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Fjern billede", + "confirm": "Er du sikker på du vil fjerne billedet?", "notification": { "success": { - "message": "" + "message": "Billedet blev fjernet" }, "error": { - "message": "" + "message": "Kan ikke fjerne billede" } } } @@ -157,15 +272,15 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "Profilen blev opdateret" }, "error": { - "message": "" + "message": "Ikke i stand til at opdatere profil" } } }, "delete": { - "label": "", + "label": "Slet brugeren permanent", "description": "", "confirm": "" }, @@ -188,23 +303,23 @@ }, "permission": { "admin": { - "title": "", + "title": "Admin", "item": { "admin": { - "label": "", - "description": "" + "label": "Administrator", + "description": "Medlemmer med denne tilladelse har fuld adgang til alle funktioner og indstillinger" } } }, "app": { - "title": "", + "title": "Apps", "item": { "create": { - "label": "", - "description": "" + "label": "Opret apps", + "description": "Tillad medlemmer at oprette apps" }, "use-all": { - "label": "", + "label": "Brug alle apps", "description": "" }, "modify-all": { @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "Forrige", "next": "Næste", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Prøv igen", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Log ind", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Farezone", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -911,10 +1046,10 @@ "label": "", "option": { "row": { - "label": "" + "label": "Horisontal" }, "column": { - "label": "" + "label": "Vertikal" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Blokeret i dag", "dnsQueriesToday": "Forespørgsler i dag", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Notesbog", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Din browser understøtter ikke iframes. Opdater venligst din browser." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "Standardvisning" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "Arbejdere", + "queue": "Kø", + "statistics": "Statistikker" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "I kø", + "status": { + "healthy": "Sund", + "unhealthy": "Usund" + } + }, + "panel": { + "statistics": { + "empty": "Tom", + "transcodes": "Transkoder", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "Kodeks", + "videoContainers": "Containere", + "videoResolutions": "Opløsninger" + }, + "workers": { + "empty": "Tom", + "table": { + "file": "Fil", + "eta": "", + "progress": "Fremskridt", + "transcode": "Transkod", + "healthCheck": "" + } + }, + "queue": { + "empty": "Tom", + "table": { + "file": "Fil", + "size": "Størrelse", + "transcode": "Transkod", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Lille", "md": "Mellem", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Slet permanent", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Generelt", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Første ugedag", "accessibility": "Hjælpefunktioner" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Generelt", - "owner": "", + "owner": "Ejer", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2081,12 +2363,20 @@ "board": { "title": "", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Udseende", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Fejl" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/de.json b/packages/translation/src/lang/de.json index e8bcf21d7..2a9c36e86 100644 --- a/packages/translation/src/lang/de.json +++ b/packages/translation/src/lang/de.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "Willkommen bei Homarr", + "subtitle": "Lass uns mit der Einrichtung deiner Homarr-Instanz beginnen.", + "description": "Um loszulegen, wähle bitte wie du deine Homarr Instanz einrichten möchtest.", + "action": { + "scratch": "Von vorne beginnen", + "importOldmarr": "Import von Homarr vor 1.0" + } + }, + "import": { + "title": "Daten importieren", + "subtitle": "Sie können Daten aus einer bestehenden Homarr-Instanz importieren.", + "dropzone": { + "title": "Ziehen Sie die Zip-Datei hierher oder klicken Sie zum Durchsuchen", + "description": "Die hochgeladene Zip-Datei wird bearbeitet und Sie können wählen, was Sie importieren möchten" + }, + "fileInfo": { + "action": { + "change": "Datei ändern" + } + }, + "importSettings": { + "title": "Importeinstellungen", + "description": "Importverhalten konfigurieren" + }, + "boardSelection": { + "title": "{count} Boards gefunden", + "description": "Wählen Sie alle Boards mit der Größe aus, die Sie importieren möchten", + "action": { + "selectAll": "Alles auswählen", + "unselectAll": "Gesamte Auswahl aufheben" + } + }, + "summary": { + "title": "Zusammenfassung des Imports", + "description": "In der folgenden Zusammenfassung sehen Sie, was importiert wird", + "action": { + "import": "Import bestätigen und fortfahren" + }, + "entities": { + "apps": "Applikationen", + "boards": "Boards", + "integrations": "Integrationen", + "credentialUsers": "Benutzer mit Zugangsdaten" + } + }, + "tokenModal": { + "title": "Importschlüssel eingeben", + "field": { + "token": { + "label": "Schlüssel", + "description": "Gib den angezeigten Importschlüssel von der vorherigen Homarr-Instanz ein" + } + }, + "notification": { + "error": { + "title": "Ungültiger Schlüssel", + "message": "Der eingegebene Schlüssel ist ungültig" + } + } + } + }, + "user": { + "title": "Administrator", + "subtitle": "Geben Sie die Zugangsdaten für Ihren Administrator-Benutzer an.", + "notification": { + "success": { + "title": "Benutzer erstellt", + "message": "Der Benutzer wurde erfolgreich erstellt" + }, + "error": { + "title": "Erstellung des Benutzers fehlgeschlagen" + } + } + }, + "group": { + "title": "Externe Gruppe", + "subtitle": "Gebe die Gruppe an, welche für externe Benutzer verwendet werden soll.", + "form": { + "name": { + "label": "Gruppenname", + "description": "Name muss mit der Admin-Gruppe des externen Anbieters übereinstimmen" + } + } + }, + "settings": { + "title": "Einstellungen", + "subtitle": "Server-Einstellungen konfigurieren." + }, + "finish": { + "title": "Einrichtung abschließen", + "subtitle": "Es kann losgehen!", + "description": "Du hast die Einrichtung erfolgreich abgeschlossen. Du kannst jetzt mit der Nutzung von Homarr beginnen. Wähle deine nächste Aktion:", + "action": { + "goToBoard": "Gehe zu {name} Board", + "createBoard": "Erstelle dein erstes Board", + "inviteUser": "Andere Benutzer einladen", + "docs": "Lese die Dokumentation" + } + } + }, + "backToStart": "Zurück zum Anfang" + }, "user": { "title": "Benutzer", "name": "Benutzer", @@ -8,7 +113,7 @@ "subtitle": "Willkommen zurück! Bitte gib deine Zugangsdaten ein" }, "invite": { - "title": "Trete Homarr bei", + "title": "Homarr beitreten", "subtitle": "Willkommen bei Homarr! Bitte erstelle dein Konto", "description": "Du wurdest von {username} eingeladen" }, @@ -19,7 +124,7 @@ }, "field": { "email": { - "label": "", + "label": "E-Mail", "verified": "Verifiziert" }, "username": { @@ -42,10 +147,10 @@ "label": "Vorheriges Passwort" }, "homeBoard": { - "label": "" + "label": "Home Board" }, "pingIconsEnabled": { - "label": "" + "label": "Symbole für Pings verwenden" } }, "error": { @@ -91,65 +196,75 @@ "message": "Passwort erfolgreich geändert" }, "error": { - "message": "" + "message": "Passwort konnte nicht geändert werden" } } }, "changeHomeBoard": { "notification": { "success": { - "message": "" + "message": "Home Board erfolgreich geändert" }, "error": { - "message": "" + "message": "Home Board konnte nicht geändert werden" + } + } + }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "Standard-Suchmaschine erfolgreich geändert" + }, + "error": { + "message": "Standard Suchmaschine kann nicht geändert werden" } } }, "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "Erster Wochentag erfolgreich geändert" }, "error": { - "message": "" + "message": "Konnte den ersten Wochentag nicht ändern" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "Ping Icons erfolgreich umgeschaltet" }, "error": { - "message": "" + "message": "Konnte Ping-Icons nicht umschalten" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Bild ändern", "notification": { "success": { - "message": "" + "message": "Der Name wurde erfolgreich geändert" }, "error": { - "message": "" + "message": "Bild konnte nicht geändert werden" }, "toLarge": { - "title": "", - "message": "" + "title": "Bild ist zu groß", + "message": "Maximale Bildgröße ist {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Bild entfernen", + "confirm": "Wollen Sie wirklich dieses Bild entfernen?", "notification": { "success": { - "message": "" + "message": "Bild erfolgreich entfernt" }, "error": { - "message": "" + "message": "Bild kann nicht entfernt werden" } } } @@ -157,454 +272,463 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "Profil wurde aktualisiert" }, "error": { - "message": "" + "message": "Aktualisierung des Profils fehlgeschlagen" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "Benutzer dauerhaft löschen", + "description": "Löscht diesen Benutzer einschließlich seiner Einstellungen. Wird keine Boards löschen. Benutzer wird nicht benachrichtigt.", + "confirm": "Sind Sie sicher, dass Sie den Benutzer {username} mit seinen Einstellungen löschen möchten?" }, "select": { - "label": "", - "notFound": "" + "label": "Benutzer auswählen", + "notFound": "Kein Benutzer gefunden" }, "transfer": { - "label": "" + "label": "Neuen Eigentümer auswählen" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "Benutzergruppen", + "name": "Benutzergruppe", + "search": "Finde eine Benutzergruppe", "field": { - "name": "", - "members": "" + "name": "Name", + "members": "Mitglieder" }, "permission": { "admin": { - "title": "", + "title": "Admin", "item": { "admin": { - "label": "", - "description": "" + "label": "Administrator", + "description": "Mitglieder mit dieser Berechtigung haben vollen Zugriff auf alle Funktionen und Einstellungen" } } }, "app": { - "title": "", + "title": "Apps", "item": { "create": { - "label": "", - "description": "" + "label": "Apps erstellen", + "description": "Mitgliedern das Erstellen von Apps erlauben" }, "use-all": { - "label": "", - "description": "" + "label": "Alle Apps verwenden", + "description": "Mitgliedern erlauben, Apps zu ihren Boards hinzuzufügen" }, "modify-all": { - "label": "", - "description": "" + "label": "Alle Apps ändern", + "description": "Mitgliedern das Erstellen von Apps erlauben" }, "full-all": { - "label": "", - "description": "" + "label": "Voller App Zugriff", + "description": "Mitgliedern das Benutzen, Verwalten und Löschen von Apps erlauben" } } }, "board": { - "title": "", + "title": "Boards", "item": { "create": { - "label": "", - "description": "" + "label": "Boards erstellen", + "description": "Mitgliedern das Erstellen von Boards erlauben" }, "view-all": { - "label": "", - "description": "" + "label": "Alle Boards anzeigen", + "description": "Mitgliedern das Ansehen von Boards erlauben" }, "modify-all": { - "label": "", - "description": "" + "label": "Alle Boards ändern", + "description": "Erlaube Mitgliedern alle Boards zu ändern (beinhaltet keine Zugangskontrolle und Gefahrenbereich)" }, "full-all": { - "label": "", - "description": "" + "label": "Voller Board Zugriff", + "description": "Erlaube Mitgliedern alle Boards (einschließlich Zugriffskontrolle und Gefahrenbereich) anzuzeigen, zu ändern und zu löschen" } } }, "integration": { - "title": "", + "title": "Integrationen", "item": { "create": { - "label": "", - "description": "" + "label": "Integrationen erstellen", + "description": "Mitgliedern erlauben, Integrationen zu erstellen" }, "use-all": { - "label": "", - "description": "" + "label": "Alle Integrationen nutzen", + "description": "Erlaubt Mitgliedern Integrationen zu ihren Boards hinzuzufügen" }, "interact-all": { - "label": "", - "description": "" + "label": "Mit jeder Integration interagieren", + "description": "Mitgliedern erlauben, mit jeder Integration zu interagieren" }, "full-all": { - "label": "", - "description": "" + "label": "Voller Zugriff auf Integrationen", + "description": "Erlaube Mitgliedern jede Integration zu verwalten, zu nutzen und zu interagieren" } } }, "media": { - "title": "", + "title": "Medien", "item": { "upload": { - "label": "", - "description": "" + "label": "Medien Hochladen", + "description": "Erlaube Mitgliedern Medien hochzuladen" }, "view-all": { - "label": "", - "description": "" + "label": "Alle Medien anzeigen", + "description": "Erlaubt Mitgliedern alle Medien anzusehen" }, "full-all": { - "label": "", - "description": "" + "label": "Vollständiger Medienzugriff", + "description": "Mitgliedern das Verwalten und Löschen von Medien erlauben" } } }, "other": { - "title": "", + "title": "Andere", "item": { "view-logs": { - "label": "", - "description": "" + "label": "Logs anzeigen", + "description": "Erlaubt Mitgliedern Logs anzusehen" } } }, "search-engine": { - "title": "", + "title": "Suchmaschinen", "item": { "create": { - "label": "", - "description": "" + "label": "Suchmaschinen anlegen", + "description": "Erlaubt es Mitgliedern Suchmaschinen anzulegen" }, "modify-all": { - "label": "", - "description": "" + "label": "Alle Suchmaschinen ändern", + "description": "Mitgliedern erlauben alle Suchmaschinen zu ändern" }, "full-all": { - "label": "", - "description": "" + "label": "Voller Zugriff auf Suchmaschinen", + "description": "Mitgliedern das Verwalten und Löschen von Suchmaschinen erlauben" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "Einige Mitglieder haben externe Anmeldeoptionen genutzt und können von hier aus nicht verwaltet werden", + "external": "Alle Mitglieder haben externe Anmeldeoptionen genutzt und können von hier aus nicht verwaltet werden" }, "reservedNotice": { - "message": "" + "message": "Diese Gruppe ist für die Systemnutzung reserviert und beschränkt einige Aktionen. " }, "action": { "create": { - "label": "", + "label": "Neue Gruppe", "notification": { "success": { - "message": "" + "message": "Die Gruppe wurde erfolgreich erstellt" }, "error": { - "message": "" + "message": "Die Gruppe konnte nicht erstellt werden" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "Eigentum übertragen", + "description": "Übertrage den Eigentümer dieser Gruppe an einen anderen Benutzer.", + "confirm": "Bist du sicher, dass du das Eigentum für die Gruppe {name} an {username} übertragen möchtest?", "notification": { "success": { - "message": "" + "message": "Gruppe {group} erfolgreich an {user} übertragen" }, "error": { - "message": "" + "message": "Übertragung des Eigentums nicht möglich" } } }, "addMember": { - "label": "" + "label": "Mitglied hinzufügen" }, "removeMember": { - "label": "", - "confirm": "" + "label": "Mitglied entfernen", + "confirm": "Bist du sicher, dass du {user} aus dieser Gruppe entfernen möchtest?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "Gruppe löschen", + "description": "Sobald Sie einen Arbeitsbereich löschen, gibt es keinen Weg sie wiederherzustellen. Bitte seien Sie sich dessen bewusst.", + "confirm": "Sind Sie sicher, dass Sie die Gruppe {name} löschen möchten?", "notification": { "success": { - "message": "" + "message": "Gruppe {name} erfolgreich gelöscht" }, "error": { - "message": "" + "message": "Gruppe {name} konnte nicht gelöscht werden" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "Berechtigungen gespeichert", + "message": "Berechtigungen wurden erfolgreich gespeichert" }, "error": { - "title": "", - "message": "" + "title": "Berechtigungen nicht gespeichert", + "message": "Berechtigungen wurden nicht gespeichert" } } }, "update": { "notification": { "success": { - "message": "" + "message": "Die Gruppe {name} wurde erfolgreich gespeichert" }, "error": { - "message": "" + "message": "Gruppe {name} konnte nicht gespeichert werden" } } }, "select": { - "label": "", - "notFound": "" + "label": "Gruppe auswählen", + "notFound": "Keine Gruppe gefunden" } } }, "app": { + "search": "App suchen", "page": { "list": { - "title": "", + "title": "Apps", "noResults": { - "title": "", - "action": "" + "title": "Noch keine Apps vorhanden", + "action": "Erstelle deine erste App" } }, "create": { - "title": "", + "title": "Neue App", "notification": { "success": { - "title": "", - "message": "" + "title": "Erstellung erfolgreich", + "message": "Die App wurde erfolgreich erstellt" }, "error": { - "title": "", - "message": "" + "title": "Erstellung fehlgeschlagen", + "message": "Die App konnte nicht angelegt werden" } } }, "edit": { - "title": "", + "title": "App bearbeiten", "notification": { "success": { - "title": "", - "message": "" + "title": "Änderungen erfolgreich angewendet", + "message": "Die App wurde erfolgreich gespeichert" }, "error": { - "title": "", - "message": "" + "title": "Änderungen konnten nicht angewendet werden", + "message": "Die App konnte nicht gespeichert werden" } } }, "delete": { - "title": "", - "message": "", + "title": "App löschen", + "message": "Sind Sie sicher, dass Sie die App {name} löschen möchten?", "notification": { "success": { - "title": "", - "message": "" + "title": "Löschen erfolgreich", + "message": "Die App wurde erfolgreich gelöscht" }, "error": { - "title": "", - "message": "" + "title": "Löschen fehlgeschlagen", + "message": "App konnte nicht gelöscht werden" } } } }, "field": { "name": { - "label": "" + "label": "Name" }, "description": { - "label": "" + "label": "Beschreibung" }, "url": { - "label": "" + "label": "URL" } }, "action": { "select": { - "label": "", - "notFound": "" + "label": "App auswählen", + "notFound": "Keine App gefunden" } } }, "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "Integrationen", + "search": "Integrationen durchsuchen", "noResults": { - "title": "" + "title": "Es gibt noch keine Integrationen" } }, "create": { - "title": "", + "title": "Neue {name} Integration", "notification": { "success": { - "title": "", - "message": "" + "title": "Erstellung erfolgreich", + "message": "Die Integration wurde erfolgreich erstellt" }, "error": { - "title": "", - "message": "" + "title": "Erstellung fehlgeschlagen", + "message": "Die Integration konnte nicht erstellt werden" } } }, "edit": { - "title": "", + "title": "{name} Integration bearbeiten", "notification": { "success": { - "title": "", - "message": "" + "title": "Änderungen erfolgreich angewendet", + "message": "Die Integration wurde erfolgreich gespeichert" }, "error": { - "title": "", - "message": "" + "title": "Änderungen konnten nicht angewendet werden", + "message": "Die Integration konnte nicht gespeichert werden" } } }, "delete": { - "title": "", - "message": "", + "title": "Integration löschen", + "message": "Sind Sie sicher, dass Sie die Integration {name} löschen möchten?", "notification": { "success": { - "title": "", - "message": "" + "title": "Löschen erfolgreich", + "message": "Die Integration wurde erfolgreich erstellt" }, "error": { - "title": "", - "message": "" + "title": "Löschen fehlgeschlagen", + "message": "Integration konnte nicht gelöscht werden" } } } }, "field": { "name": { - "label": "" + "label": "Name" }, "url": { - "label": "" + "label": "URL" + }, + "attemptSearchEngineCreation": { + "label": "Suchmaschinen anlegen", + "description": "Integration \"{kind}\" kann mit den Suchmaschinen verwendet werden. Wählen Sie dies, um die Suchmaschine automatisch zu konfigurieren." } }, "action": { - "create": "" + "create": "Neue Integration" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "Verbindung erstellen und testen", + "edit": "Verbindung erstellen und speichern" }, - "alertNotice": "", + "alertNotice": "Der Speichern Button ist verfügbar, sobald eine erfolgreiche Verbindung hergestellt wurde", "notification": { "success": { - "title": "", - "message": "" + "title": "Verbindung hergestellt", + "message": "Die Verbindung wurde erfolgreich hergestellt" }, "invalidUrl": { "title": "Ungültige URL", - "message": "" + "message": "Die Adresse ist ungültig" }, "secretNotDefined": { - "title": "", - "message": "" + "title": "Fehlende Anmeldedaten", + "message": "Nicht alle Zugangsdaten wurden angegeben" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "Ungültige Zugangsdaten", + "message": "Die Zugangsdaten sind ungültig" }, "commonError": { - "title": "", - "message": "" + "title": "Verbindungsaufbau fehlgeschlagen", + "message": "Die Verbindung konnte nicht hergestellt werden" }, "badRequest": { - "title": "", - "message": "" + "title": "Fehlerhafte Anfrage", + "message": "Die Anfrage war fehlerhaft" }, "unauthorized": { - "title": "", - "message": "" + "title": "Nicht autorisiert", + "message": "Wahrscheinlich falsche Anmeldeinformationen" }, "forbidden": { - "title": "", - "message": "" + "title": "Verweigert", + "message": "Vermutlich fehlende Berechtigungen" }, "notFound": { - "title": "", - "message": "" + "title": "Nicht gefunden", + "message": "Wahrscheinlich falsche URL oder Pfad" }, "internalServerError": { - "title": "", - "message": "" + "title": "Interner Serverfehler", + "message": "Auf dem Server ist ein Fehler aufgetreten" }, "serviceUnavailable": { - "title": "", - "message": "" + "title": "Dienst nicht verfügbar", + "message": "Der Server ist derzeit nicht erreichbar" }, "connectionAborted": { - "title": "", - "message": "" + "title": "Verbindung abgebrochen", + "message": "Die Verbindung wurde abgebrochen" }, "domainNotFound": { - "title": "", - "message": "" + "title": "Domain nicht gefunden", + "message": "Die Domain konnte nicht gefunden werden" }, "connectionRefused": { - "title": "", - "message": "" + "title": "Verbindung verweigert", + "message": "Die Verbindung wurde abgelehnt" }, "invalidJson": { - "title": "", - "message": "" + "title": "Ungültiges JSON", + "message": "Die Antwort war ungültig JSON" }, "wrongPath": { - "title": "", - "message": "" + "title": "Falscher Pfad", + "message": "Der Pfad ist vermutlich nicht korrekt" } } }, "secrets": { - "title": "", - "lastUpdated": "", - "secureNotice": "", + "title": "Secrets", + "lastUpdated": "Zuletzt aktualisiert am {date}", + "notSet": { + "label": "Kein Wert festgelegt", + "tooltip": "Das erforderliche Secret wurde noch nicht festgelegt" + }, + "secureNotice": "Das Secret kann nicht nach der Erstellung abgerufen werden", "reset": { - "title": "", - "message": "" + "title": "Secret zurücksetzen", + "message": "Bist du sicher, dass du dieses Secret zurücksetzen möchtest?" }, "noSecretsRequired": { - "segmentTitle": "", - "text": "" + "segmentTitle": "Keine Secrets", + "text": "Kein Secret für diese Integration erforderlich" }, "kind": { "username": { "label": "Benutzername", - "newLabel": "" + "newLabel": "Neuer Benutzername" }, "apiKey": { - "label": "", - "newLabel": "" + "label": "API Schlüssel", + "newLabel": "neuer API Schlüssel" }, "password": { "label": "Passwort", @@ -613,134 +737,142 @@ } }, "permission": { - "use": "", - "interact": "", - "full": "" + "use": "Integrationen in Elementen auswählen", + "interact": "Mit Integrationen interagieren", + "full": "Voller Zugriff auf Integrationen" } }, "media": { - "plural": "", - "search": "", + "plural": "Medien", + "search": "Medien suchen", "field": { - "name": "", + "name": "Name", "size": "Größe", "creator": "Ersteller" }, "action": { "upload": { - "label": "", - "file": "", + "label": "Medien Hochladen", + "file": "Datei auswählen", "notification": { "success": { - "message": "" + "message": "Das Medium wurde erfolgreich hochgeladen" }, "error": { - "message": "" + "message": "Das Medium konnte nicht hochgeladen werden" } } }, "delete": { - "label": "", - "description": "", + "label": "Medium löschen", + "description": "Sind Sie sicher, dass Sie die Medien löschen möchten?", "notification": { "success": { - "message": "" + "message": "Das Medium wurde erfolgreich gelöscht" }, "error": { - "message": "" + "message": "Die Medien konnten nicht gelöscht werden" } } }, "copy": { - "label": "" + "label": "URL in Zwischenablage kopieren" } } }, "common": { - "beta": "", + "beta": "Beta", "error": "Fehler", "action": { "add": "Hinzufügen", "apply": "Übernehmen", - "backToOverview": "", + "backToOverview": "Zurück zur Übersicht", "create": "Erstellen", "edit": "Bearbeiten", - "import": "", + "import": "Import", "insert": "Einfügen", "remove": "Entfernen", "save": "Speichern", "saveChanges": "Änderungen speichern", "cancel": "Abbrechen", "delete": "Löschen", - "discard": "", + "discard": "Verwerfen", "confirm": "Bestätigen", - "continue": "", + "continue": "Fortfahren", "previous": "Zurück", "next": "Weiter", - "checkoutDocs": "", + "checkoutDocs": "Die Dokumentation ansehen", + "checkLogs": "Logs für weitere Details prüfen", "tryAgain": "Erneut versuchen", - "loading": "" + "loading": "Wird geladen" }, - "here": "", + "here": "Hier", "iconPicker": { - "label": "", - "header": "" + "label": "Icon URL", + "header": "Geben Sie Namen oder Objekte ein, um nach Symbolen zu filtern... Homarr sucht nach {countIcons} Icons für Sie." + }, + "colorScheme": { + "options": { + "light": "Hell", + "dark": "Dunkel" + } }, "information": { - "min": "", - "max": "", - "days": "", + "min": "Min", + "max": "Max", + "days": "Tage", "hours": "Stunden", "minutes": "Minuten" }, "notification": { "create": { - "success": "", - "error": "" + "success": "Erstellung erfolgreich", + "error": "Erstellung fehlgeschlagen" }, "delete": { - "success": "", - "error": "" + "success": "Löschen erfolgreich", + "error": "Löschen fehlgeschlagen" }, "update": { - "success": "", - "error": "" + "success": "Änderungen erfolgreich angewendet", + "error": "Änderungen konnten nicht angewendet werden" }, "transfer": { - "success": "", - "error": "" + "success": "Übertragung erfolgreich", + "error": "Übertragung ist fehlgeschlagen" } }, "multiSelect": { - "placeholder": "" + "placeholder": "Wählen Sie einen oder mehrere Werte" }, "multiText": { - "placeholder": "", - "addLabel": "" + "placeholder": "Weitere Werte hinzufügen", + "addLabel": "{value} hinzufügen" }, "select": { - "placeholder": "", + "placeholder": "Wert auswählen", "badge": { - "recommended": "" + "recommended": "Empfohlen" } }, "userAvatar": { "menu": { - "switchToDarkMode": "", - "switchToLightMode": "", - "management": "", + "switchToDarkMode": "Zum dunklen Design wechseln", + "switchToLightMode": "Zum hellen Design wechseln", + "management": "Verwaltung", "preferences": "Ihre Einstellungen", - "logout": "", + "logout": "Abmelden", "login": "Anmelden", - "homeBoard": "", - "loggedOut": "" + "homeBoard": "Ihr Home Board", + "loggedOut": "Abgemeldet", + "updateAvailable": "{countUpdates} Updates verfügbar: {tag}" } }, - "dangerZone": "Gefahrenzone", + "dangerZone": "Gefahrenbereich", "noResults": "Die Suche ergab keine Treffer", "preview": { - "show": "", - "hide": "" + "show": "Vorschau ansehen", + "hide": "Vorschau ausblenden" }, "zod": { "errors": { @@ -750,7 +882,7 @@ "startsWith": "Dieses Feld muss mit {startsWith} beginnen", "endsWith": "Dieses Feld muss mit {endsWith} enden", "includes": "Dieses Feld muss {includes} beinhalten", - "invalidEmail": "" + "invalidEmail": "Dieses Feld beinhaltet keine gültige E-Mail-Adresse" }, "tooSmall": { "string": "Dieses Feld muss mindestens {minimum} Zeichen lang sein", @@ -761,12 +893,14 @@ "number": "Dieses Feld muss größer oder gleich {maximum} sein" }, "custom": { - "passwordsDoNotMatch": "", - "passwordRequirements": "", - "boardAlreadyExists": "", - "invalidFileType": "", - "fileTooLarge": "", - "invalidConfiguration": "" + "passwordsDoNotMatch": "Passwörter stimmen nicht überein", + "passwordRequirements": "Passwort erfüllt nicht alle Anforderungen", + "boardAlreadyExists": "Ein Board mit diesem Namen existiert bereits", + "invalidFileType": "Ungültiger Dateityp, erwartete {expected}", + "invalidFileName": "", + "fileTooLarge": "Datei ist zu groß, maximale Größe ist {maxSize}", + "invalidConfiguration": "Ungültige Konfiguration", + "groupNameTaken": "Gruppenname bereits vergeben" } } } @@ -774,44 +908,44 @@ "section": { "dynamic": { "action": { - "create": "", - "remove": "" + "create": "Neuer dynamischer Abschnitt", + "remove": "Dynamischen Abschnitt entfernen" }, "remove": { - "title": "", - "message": "" + "title": "Dynamischen Abschnitt entfernen", + "message": "Möchten Sie diesen dynamischen Abschnitt wirklich entfernen? Die Elemente werden an die gleiche Position im übergeordneten Abschnitt verschoben." } }, "category": { "field": { "name": { - "label": "" + "label": "Name" } }, "action": { - "create": "", - "edit": "", - "remove": "", + "create": "Neue Kategorie", + "edit": "Kategorie umbenennen", + "remove": "Kategorie entfernen", "moveUp": "Nach oben bewegen", "moveDown": "Nach unten bewegen", - "createAbove": "", - "createBelow": "" + "createAbove": "Neue Kategorie oben", + "createBelow": "Neue Kategorie unten" }, "create": { - "title": "", - "submit": "" + "title": "Neue Kategorie", + "submit": "Kategorie hinzufügen" }, "remove": { - "title": "", - "message": "" + "title": "Kategorie entfernen", + "message": "Möchten Sie die Kategorie {name} wirklich entfernen?" }, "edit": { - "title": "", - "submit": "" + "title": "Kategorie umbenennen", + "submit": "Kategorie umbenennen" }, "menu": { "label": { - "create": "", + "create": "Neue Kategorie", "changePosition": "Position wechseln" } } @@ -819,12 +953,12 @@ }, "item": { "action": { - "create": "", - "import": "", - "edit": "", - "moveResize": "", - "duplicate": "", - "remove": "" + "create": "Neues Element", + "import": "Element importieren", + "edit": "Element bearbeiten", + "moveResize": "Element verschieben/Größe ändern", + "duplicate": "Element duplizieren", + "remove": "Element löschen" }, "menu": { "label": { @@ -832,11 +966,12 @@ } }, "create": { - "title": "", - "addToBoard": "" + "title": "Wählen Sie das hinzuzufügende Element aus", + "search": "Gegenstände filtern", + "addToBoard": "Zum Board hinzufügen" }, "moveResize": { - "title": "", + "title": "Element verschieben/Größe ändern", "field": { "width": { "label": "Breite" @@ -845,197 +980,217 @@ "label": "Höhe" }, "xOffset": { - "label": "" + "label": "X Versatz" }, "yOffset": { - "label": "" + "label": "Y Versatz" } } }, "edit": { - "title": "", + "title": "Element bearbeiten", "advancedOptions": { - "label": "", - "title": "" + "label": "Erweiterte Einstellungen", + "title": "Erweiterte Einstellungen Optionen" }, "field": { "integrations": { - "label": "" + "label": "Integrationen" }, "customCssClasses": { - "label": "" + "label": "Benutzerdefinierte CSS Klassen" } } }, "remove": { - "title": "", - "message": "" + "title": "Element entfernen", + "message": "Soll dieses Element wirklich entfernt werden?" } }, "widget": { "app": { - "name": "", - "description": "", + "name": "App", + "description": "Bettet eine App in das Board ein.", "option": { "appId": { - "label": "" + "label": "App auswählen" }, "openInNewTab": { "label": "In neuem Tab öffnen" }, "showTitle": { - "label": "" + "label": "App Namen anzeigen" }, "showDescriptionTooltip": { - "label": "" + "label": "Beschreibungs des Tooltips anzeigen" }, "pingEnabled": { - "label": "" + "label": "Einfachen Ping aktivieren" } }, "error": { "notFound": { - "label": "", - "tooltip": "" + "label": "Keine App", + "tooltip": "Sie haben keine gültige App ausgewählt" } } }, "bookmarks": { - "name": "", - "description": "", + "name": "Lesezeichen", + "description": "Mehrere App Links anzeigen", "option": { "title": { - "label": "" + "label": "Titel" }, - "layout": { - "label": "", - "option": { - "row": { - "label": "" - }, - "column": { - "label": "" - }, - "grid": { - "label": "" - } - } - }, - "items": { - "label": "", - "add": "" - } - } - }, - "dnsHoleSummary": { - "name": "", - "description": "", - "option": { "layout": { "label": "Ansicht", "option": { "row": { - "label": "" + "label": "Horizontal" }, "column": { "label": "Vertikal" }, "grid": { - "label": "" + "label": "Raster" + } + } + }, + "items": { + "label": "Lesezeichen", + "add": "Lesezeichen hinzufügen" + } + } + }, + "dnsHoleSummary": { + "name": "DNS Hole Zusammenfassung", + "description": "Zeigt die Zusammenfassung deines DNS Holes an", + "option": { + "layout": { + "label": "Ansicht", + "option": { + "row": { + "label": "Horizontal" + }, + "column": { + "label": "Vertikal" + }, + "grid": { + "label": "Raster" } } }, "usePiHoleColors": { - "label": "" + "label": "Pi Hole Farben verwenden" } }, "error": { - "internalServerError": "", - "integrationsDisconnected": "" + "internalServerError": "Fehler beim Abrufen der DNS Hole Zusammenfassung", + "integrationsDisconnected": "Keine Daten verfügbar, alle Integrationen getrennt" }, "data": { "adsBlockedToday": "Heute blockiert", "adsBlockedTodayPercentage": "Heute blockiert", - "dnsQueriesToday": "Heutige Anfragen", - "domainsBeingBlocked": "" - } + "dnsQueriesToday": "Abfragen heute", + "domainsBeingBlocked": "Domänen auf der Sperrliste" + }, + "domainsTooltip": "Aufgrund mehrerer Integrationen kann Homarr die genaue Anzahl der blockierten Domains nicht berechnen" }, "dnsHoleControls": { - "name": "", + "name": "DNS Hole Steuerung", "description": "Steuern Sie PiHole oder AdGuard von Ihrem Dashboard aus", "option": { "layout": { "label": "Ansicht", "option": { "row": { - "label": "" + "label": "Horizontal" }, "column": { "label": "Vertikal" }, "grid": { - "label": "" + "label": "Raster" } } }, "showToggleAllButtons": { - "label": "" + "label": "Alle Schaltflächen anzeigen" } }, "error": { - "internalServerError": "" + "internalServerError": "Fehler bei der Kontrolle des DNS Holes" }, "controls": { - "enableAll": "", - "disableAll": "", - "setTimer": "", - "set": "Speichern", + "enableAll": "Alle aktivieren", + "disableAll": "Alle deaktivieren", + "setTimer": "Timer setzen", + "set": "Übernehmen", "enabled": "Aktiviert", "disabled": "Deaktiviert", - "processing": "", - "disconnected": "", + "processing": "Wird verarbeitet", + "disconnected": "Verbindung getrennt", "hours": "Stunden", "minutes": "Minuten", - "unlimited": "" + "unlimited": "Freilassen für unbegrenzt" } }, "clock": { - "name": "", + "name": "Datum und Uhrzeit", "description": "Zeigt das aktuelle Datum und die Uhrzeit an.", "option": { "customTitleToggle": { - "label": "", - "description": "" + "label": "Eigene Titel/Stadt Anzeige", + "description": "Zeige einen benutzerdefinierten Titel oder den Namen der Stadt oder des Landes oben auf der Uhr." }, "customTitle": { - "label": "" + "label": "Titel" }, "is24HourFormat": { - "label": "", - "description": "" + "label": "24-Stunden Format", + "description": "24-Stunden Format anstelle von 12-Stunden Format verwenden" }, "showSeconds": { - "label": "" + "label": "Sekunden anzeigen" }, "useCustomTimezone": { - "label": "" + "label": "Eine feste Zeitzone verwenden" }, "timezone": { "label": "Zeitzone", - "description": "" + "description": "Wählen Sie die Zeitzone nach dem IANA-Standard" }, "showDate": { - "label": "" + "label": "Datum anzeigen" }, "dateFormat": { - "label": "", - "description": "" + "label": "Datumsformat", + "description": "Wie das Datum aussehen sollte" } } }, + "minecraftServerStatus": { + "name": "Status des Minecraft Servers", + "description": "Status des Minecraft Servers anzeigen", + "option": { + "title": { + "label": "Titel" + }, + "domain": { + "label": "Server Adresse" + }, + "isBedrockServer": { + "label": "Bedrock Server" + } + }, + "status": { + "online": "Online", + "offline": "Offline" + } + }, "notebook": { "name": "Notizbuch", - "description": "", + "description": "Ein einfaches Notizbuch Widget, das Markdown unterstützt", "option": { "showToolbar": { "label": "Zeigt die Symbolleiste an, um Ihnen beim Schreiben der Markdown zu assistieren" @@ -1054,7 +1209,7 @@ "underline": "Unterstrichen", "colorText": "Farbiger Text", "colorHighlight": "Farbig hervorgehobener Text", - "code": "", + "code": "Code", "clear": "Formatierung entfernen", "heading": "Überschrift {level}", "align": "Text ausrichten: {position}", @@ -1065,7 +1220,7 @@ "checkList": "Checkliste", "increaseIndent": "Einzug vergrößern", "decreaseIndent": "Einzug verkleinern", - "link": "", + "link": "Verknüpfung", "unlink": "Link entfernen", "image": "Bild einbetten", "addTable": "Tabelle hinzufügen", @@ -1095,7 +1250,7 @@ } }, "iframe": { - "name": "", + "name": "iFrame", "description": "Einbetten von Inhalten aus dem Internet. Einige Websites können den Zugriff einschränken.", "option": { "embedUrl": { @@ -1127,31 +1282,32 @@ } }, "error": { - "noUrl": "", + "noUrl": "Keine iFrame URL angegeben", + "unsupportedProtocol": "Die angegebene URL verwendet ein nicht unterstütztes Protokoll. Bitte verwenden Sie eines von ({supportedProtocols})", "noBrowerSupport": "Ihr Browser unterstützt keine iframes. Bitte aktualisieren Sie Ihren Browser." } }, "smartHome-entityState": { - "name": "", - "description": "", + "name": "Zustand der Entität", + "description": "Zeigt den Status einer Entität an und schaltet ihn optional ein", "option": { "entityId": { "label": "Eintrag-ID" }, "displayName": { - "label": "" + "label": "Anzeigename" }, "entityUnit": { - "label": "" + "label": "Einheit der Entität" }, "clickable": { - "label": "" + "label": "Anklickbar" } } }, "smartHome-executeAutomation": { - "name": "", - "description": "", + "name": "Automatisierung ausführen", + "description": "Automatisierung mit einem Klick auslösen", "option": { "displayName": { "label": "Anzeigename" @@ -1161,26 +1317,26 @@ } }, "spotlightAction": { - "run": "" + "run": "{name} ausführen" } }, "calendar": { "name": "Kalender", - "description": "", + "description": "Zeigt Ereignisse aus Ihren Integrationen in einer Kalenderansicht innerhalb eines bestimmten Zeitraums an", "option": { "releaseType": { "label": "Radarr Veröffentlichungs Typ", "options": { - "inCinemas": "", - "digitalRelease": "", - "physicalRelease": "" + "inCinemas": "In Kinos", + "digitalRelease": "Digitale Veröffentlichung", + "physicalRelease": "Physische Veröffentlichung" } }, "filterPastMonths": { - "label": "" + "label": "Start von" }, "filterFutureMonths": { - "label": "" + "label": "Endet am" } } }, @@ -1189,24 +1345,24 @@ "description": "Zeigt die aktuellen Wetterinformationen für einen bestimmten Ort an.", "option": { "isFormatFahrenheit": { - "label": "" + "label": "Temperatur in Fahrenheit" }, "location": { "label": "Wetterstandort" }, "showCity": { - "label": "" + "label": "Stadt anzeigen" }, "hasForecast": { - "label": "" + "label": "Prognose anzeigen" }, "forecastDayCount": { - "label": "", - "description": "" + "label": "Anzahl der Prognose Tage", + "description": "Wenn das Widget nicht breit genug ist, werden weniger Tage angezeigt" }, "dateFormat": { - "label": "", - "description": "" + "label": "Datumsformat", + "description": "Wie das Datum aussehen sollte" } }, "kind": { @@ -1227,17 +1383,17 @@ } }, "indexerManager": { - "name": "Status des Indexer-Managers", - "description": "", + "name": "Status des Index Managers", + "description": "Status des Indexer", "option": { "openIndexerSiteInNewTab": { - "label": "" + "label": "Indexer Seite in neuem Tab öffnen" } }, - "title": "Indexer-Manager", + "title": "Index Manager", "testAll": "Alle testen", "error": { - "internalServerError": "" + "internalServerError": "Fehler beim Abrufen des Indexer Status" } }, "healthMonitoring": { @@ -1258,41 +1414,41 @@ } }, "popover": { - "information": "", - "processor": "", - "memory": "", - "memoryAvailable": "", - "version": "", - "uptime": "", - "loadAverage": "", - "minute": "", - "minutes": "", - "used": "", + "information": "Informationen", + "processor": "Prozessor: {cpuModelName}", + "memory": "Speicher: {memory}GiB", + "memoryAvailable": "Verfügbar: {memoryAvailable} GiB ({percent}%)", + "version": "Version: {version}", + "uptime": "Laufzeit: {months} Monate, {days} Tage, {hours} Stunden, {minutes} Minuten", + "loadAverage": "Durchschnittliche Last:", + "minute": "1 Minute", + "minutes": "{count} Minuten", + "used": "Belegt", "available": "Verfügbar", - "lastSeen": "" + "lastSeen": "Letzte Statusaktualisierung: {lastSeen}" }, "memory": {}, "error": { - "internalServerError": "" + "internalServerError": "Fehler beim Abrufen des Gesundheitsstatus" } }, "common": { "location": { - "query": "", - "latitude": "", - "longitude": "", - "disabledTooltip": "", - "unknownLocation": "", - "search": "Suchen", + "query": "Stadt / Postleitzahl", + "latitude": "Breitengrad", + "longitude": "Längengrad", + "disabledTooltip": "Gib eine Stadt oder Postleitzahl an", + "unknownLocation": "Unbekannter Ort", + "search": "Suche", "table": { "header": { - "city": "", - "country": "", - "coordinates": "", - "population": "" + "city": "Stadt", + "country": "Land", + "coordinates": "Koordinaten", + "population": "Bevölkerung" }, "action": { - "select": "" + "select": "Wähle {city}, {countryCode}" }, "population": { "fallback": "Unbekannt" @@ -1300,19 +1456,16 @@ } }, "integration": { - "noData": "", - "description": "" + "noData": "Keine Integration gefunden", + "description": "Klicken Sie um eine neue Integration zu erstellen" }, "app": { - "noData": "", - "description": "" + "noData": "Keine App gefunden", + "description": "Klicken Sie um eine neue App zu erstellen" }, "error": { - "action": { - "logs": "" - }, - "noIntegration": "", - "noData": "" + "noIntegration": "Keine Integration ausgewählt", + "noData": "Keine Integrationsdaten verfügbar" }, "option": {} }, @@ -1321,31 +1474,36 @@ "description": "Einbetten eines Videostreams oder eines Videos von einer Kamera oder einer Website", "option": { "feedUrl": { - "label": "Feed-URL" + "label": "Feed URL" }, "hasAutoPlay": { "label": "Automatische Wiedergabe", - "description": "" + "description": "Autoplay funktioniert nur bei Stummschaltung aufgrund von Browser Einschränkungen" }, "isMuted": { - "label": "" + "label": "Stumm geschaltet" }, "hasControls": { - "label": "" + "label": "Steuerelemente anzeigen" } }, "error": { - "noUrl": "", - "forYoutubeUseIframe": "" + "noUrl": "Keine Video URL angegeben", + "forYoutubeUseIframe": "Für YouTube Videos verwenden Sie die iframe Option" } }, "mediaServer": { - "name": "", - "description": "", - "option": {} + "name": "Aktuelle Media Server Streams", + "description": "Zeige die aktuellen Streams auf deinen Medienservern an", + "option": {}, + "items": { + "user": "Benutzer", + "name": "Name", + "id": "Id" + } }, "downloads": { - "name": "", + "name": "Download Client", "description": "", "option": { "columns": { @@ -1400,8 +1558,8 @@ "detailsTitle": "Download Geschwindigkeit" }, "index": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "#", + "detailsTitle": "Aktueller Index im Client" }, "id": { "columnTitle": "" @@ -1450,7 +1608,7 @@ } }, "states": { - "downloading": "Herunterladen", + "downloading": "Wird heruntergeladen", "queued": "In der Warteschlange", "paused": "Pausiert", "completed": "Abgeschlossen", @@ -1477,15 +1635,15 @@ "delete": { "title": "", "modalTitle": "", - "entry": "", - "entryAndFiles": "" + "entry": "Eintrag löschen", + "entryAndFiles": "Eintrag und Datei(en) löschen" } } }, - "globalRatio": "" + "globalRatio": "Globales Verhältnis" }, "mediaRequests-requestList": { - "name": "", + "name": "Liste der Medienanfragen", "description": "Sehen Sie eine Liste aller Medienanfragen von Ihrer Overseerr- oder Jellyseerr-Instanz", "option": { "linksTargetNewTab": { @@ -1493,93 +1651,166 @@ } }, "pending": { - "approve": "", - "approving": "", - "decline": "" + "approve": "Anfrage annehmen", + "approving": "Anfrage wird bestätigt...", + "decline": "Antrag ablehnen" }, "availability": { "unknown": "Unbekannt", - "pending": "", - "processing": "", + "pending": "Ausstehend", + "processing": "In Bearbeitung", "partiallyAvailable": "Teilweise", "available": "Verfügbar" }, - "toBeDetermined": "" + "toBeDetermined": "Noch Festzulegen" }, "mediaRequests-requestStats": { - "name": "", + "name": "Statistik der Medienanfragen", "description": "Statistiken über Ihre Medienanfragen", "option": {}, "titles": { "stats": { - "main": "Medien-Statistiken", + "main": "Medien Statistiken", "approved": "Bereits genehmigt", "pending": "Ausstehende Freigaben", - "processing": "", - "declined": "", - "available": "", - "tv": "TV-Anfragen", - "movie": "Film-Anfragen", + "processing": "Wird verarbeitet", + "declined": "Bereits abgelehnt", + "available": "Bereits verfügbar", + "tv": "TV Anfragen", + "movie": "Film Anfragen", "total": "Gesamt" }, "users": { - "main": "Top-Nutzer", - "requests": "" + "main": "Top Nutzer", + "requests": "Anfragen" + } + } + }, + "mediaTranscoding": { + "name": "Medien Transkodierung", + "description": "Statistiken, aktuelle Warteschlange und Status Ihrer Medien Transkordierung", + "option": { + "defaultView": { + "label": "Standardansicht" + }, + "queuePageSize": { + "label": "Größe der Warteschlange" + } + }, + "tab": { + "workers": "Arbeiter", + "queue": "Warteschlange", + "statistics": "Statistiken" + }, + "currentIndex": "{start}-{end} von {total}", + "healthCheck": { + "title": "Gesundheitscheck", + "queued": "In der Warteschlange", + "status": { + "healthy": "Gesund", + "unhealthy": "Fehlerhaft" + } + }, + "panel": { + "statistics": { + "empty": "Leer", + "transcodes": "Transkodieren", + "transcodesCount": "Transkodierung: {value}", + "healthChecksCount": "Gesundheitscheck: {value}", + "filesCount": "Dateien: {value}", + "savedSpace": "Gespeicherter Speicherplatz: {value}", + "healthChecks": "Gesundheitscheck", + "videoCodecs": "Codecs", + "videoContainers": "Container", + "videoResolutions": "Auflösungen" + }, + "workers": { + "empty": "Leer", + "table": { + "file": "Datei", + "eta": "Voraussichtlicher Abschluss", + "progress": "Fortschritt", + "transcode": "Transkodieren", + "healthCheck": "Gesundheitscheck" + } + }, + "queue": { + "empty": "Leer", + "table": { + "file": "Datei", + "size": "Größe", + "transcode": "Transkodieren", + "healthCheck": "Gesundheitscheck" + } } } }, "rssFeed": { - "name": "", - "description": "", + "name": "RSS Feeds", + "description": "Einen oder mehrere generische RSS, ATOM oder JSON-Feeds überwachen und anzeigen", "option": { "feedUrls": { - "label": "" + "label": "Feed URLs" }, "enableRtl": { - "label": "" + "label": "RTL aktivieren" }, "textLinesClamp": { - "label": "" + "label": "Beschreibung line clamp" }, "maximumAmountPosts": { - "label": "" + "label": "Limit für Beiträge" } } } }, "widgetPreview": { "toggle": { - "enabled": "", - "disabled": "" + "enabled": "Bearbeitungsmodus aktiviert", + "disabled": "Bearbeitungsmodus deaktiviert" }, "dimensions": { - "title": "" + "title": "Dimensionen ändern" } }, "board": { "action": { + "duplicate": { + "title": "Board duplizieren", + "message": "Dies wird das Board {name} mit all seinen Inhalten duplizieren. Wenn Widgets Integrationen, hinterlegt sind die Sie nicht verwenden dürfen, werden diese entfernt.", + "notification": { + "success": { + "title": "Board dupliziert", + "message": "Das Board wurde erfolgreich dupliziert" + }, + "error": { + "title": "Board konnte nicht dupliziert werden", + "message": "Das Board konnte nicht dupliziert werden" + } + } + }, "edit": { "notification": { "success": { - "title": "", - "message": "" + "title": "Änderungen erfolgreich angewendet", + "message": "Das Board wurde erfolgreich dupliziert" }, "error": { - "title": "", - "message": "" + "title": "Änderungen konnten nicht angewendet werden", + "message": "Das Board konnte nicht gespeichert werden" } }, "confirmLeave": { - "title": "", - "message": "" + "title": "Nicht gespeicherte Änderungen", + "message": "Sie haben ungespeicherte Änderungen, sind sie sicher dass sie abbrechen möchten?" } }, "oldImport": { - "label": "", + "label": "Import von Homarr vor Version 1.0.0", "notification": { "success": { - "title": "", - "message": "" + "title": "Import erfolgreich", + "message": "Das Board wurde erfolgreich importiert" }, "error": { "title": "", @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Klein", "md": "Mittel", @@ -1717,7 +1949,7 @@ "label": "" }, "isPublic": { - "label": "Öffentlich sichtbar", + "label": "Öffentlich", "description": "" } }, @@ -1738,82 +1970,114 @@ "title": "Hintergrund" }, "color": { - "title": "" + "title": "Farben" }, "customCss": { - "title": "" + "title": "Benutzerdefiniertes CSS" }, "access": { - "title": "", + "title": "Zugriffskontrolle", "permission": { "item": { "view": { "label": "Board anzeigen" }, "modify": { - "label": "" + "label": "Board bearbeiten" }, "full": { - "label": "" + "label": "Voller Zugriff" } } } }, "dangerZone": { - "title": "Gefahrenzone", + "title": "Gefahrenbereich", "action": { "rename": { - "label": "", - "description": "", - "button": "", + "label": "Board umbenennen", + "description": "Das Ändern des Namens wird alle Links zu diesem Board aufheben.", + "button": "Namen ändern", "modal": { - "title": "" + "title": "Board umbenennen" } }, "visibility": { - "label": "", + "label": "Sichtbarkeit des Boards ändern", "description": { - "public": "", - "private": "" + "public": "Dieses Board ist derzeit öffentlich.", + "private": "Dieses Board ist derzeit privat." }, "button": { - "public": "", - "private": "" + "public": "Als privat festlegen", + "private": "Als öffentlich festlegen" }, "confirm": { "public": { - "title": "", - "description": "" + "title": "Board auf privat schalten", + "description": "Sind Sie sicher, dass Sie dieses Board privat machen möchten? Dies wird das Board vor der Öffentlichkeit ausblenden. Links für Gastbenutzer werden unbrauchbar." }, "private": { - "title": "", - "description": "" + "title": "Board auf öffentlich schalten", + "description": "Sind Sie sicher, dass Sie dieses Board öffentlich machen möchten? Dies wird das Board für alle zugänglich machen." } } }, "delete": { - "label": "", - "description": "", - "button": "", + "label": "Board löschen", + "description": "Sobald Sie ein Board löschen, gibt es kein zurück mehr. Bitte seien sie sich dessen bewusst.", + "button": "Board löschen", "confirm": { "title": "Board löschen", - "description": "" + "description": "Sind Sie sicher, dass Sie dieses Board löschen möchten? Dies wird das Board und seinen gesamten Inhalt permanent löschen." } } } } } + }, + "error": { + "noBoard": { + "title": "Willkommen bei Homarr", + "description": "Ein schlankens, modernes Dashboard, das alle Ihre Apps und Dienste bereit stellt.", + "link": "Erstellen Sie Ihr erstes Board", + "notice": "Um diese Seite verschwinden zu lassen, erstellen Sie ein Board und setzen es als Home Board" + }, + "notFound": { + "title": "Board nicht gefunden", + "description": "Das angegebene Board wurde entweder nicht gefunden oder Sie haben keinen Zugriff darauf.", + "link": "Alle Boards anzeigen", + "notice": "Überprüfen Sie den Link oder wenden Sie sich an einen Administrator, wenn Sie glauben, dass er zugänglich sein sollte" + }, + "homeBoard": { + "title": "Kein Home Board", + "admin": { + "description": "Es wurde noch kein Home Board für den Server festgelegt.", + "link": "Serverweites Home Board konfigurieren", + "notice": "Um diese Seite für alle Benutzer verschwinden zu lassen, legen sie ein Home-Board für den Server fest" + }, + "user": { + "description": "Es wurde noch kein Home Board festgelegt.", + "link": "Home Board konfigurieren", + "notice": "Um diese Seite verschwinden zu lassen, geben Sie das Home Board in Ihren Einstellungen ein" + }, + "anonymous": { + "description": "Der Server-Administrator hat noch kein Home Board eingerichtet.", + "link": "Öffentliche Boards anzeigen", + "notice": "Um diese Seite verschwinden zu lassen, bitten sie den Server Administrator, ein Home Board für den Server festzulegen" + } + } } }, "management": { - "metaTitle": "", + "metaTitle": "Verwaltung", "title": { - "morning": "", - "afternoon": "", - "evening": "" + "morning": "Guten Morgen, {username}", + "afternoon": "Guten Nachmittag, {username}", + "evening": "Guten Abend, {username}" }, "notFound": { - "title": "", + "title": "Nicht gefunden", "text": "" }, "navbar": { @@ -1821,15 +2085,15 @@ "home": "Startseite", "boards": "", "apps": "", - "integrations": "", - "searchEngies": "", - "medias": "", + "integrations": "Integrationen", + "searchEngies": "Suchmaschinen", + "medias": "Medien", "users": { "label": "Benutzer", "items": { "manage": "Verwalten", "invites": "Einladungen", - "groups": "" + "groups": "Gruppen" } }, "tools": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1860,9 +2125,9 @@ "board": "", "user": "Benutzer", "invite": "Einladungen", - "integration": "", + "integration": "Integrationen", "app": "", - "group": "" + "group": "Gruppen" }, "statisticLabel": { "boards": "", @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Dauerhaft löschen", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Allgemein", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Erster Tag der Woche", "accessibility": "Barrierefreiheit" } @@ -1953,7 +2235,7 @@ "label": "Sicherheit" }, "groups": { - "label": "", + "label": "Gruppen", "title": "", "description": "" }, @@ -1961,10 +2243,10 @@ "label": "" }, "completed": { - "title": "" + "title": "Benutzer erstellt" }, "error": { - "title": "" + "title": "Erstellung des Benutzers fehlgeschlagen" } }, "action": { @@ -1977,7 +2259,7 @@ "action": { "new": { "title": "", - "description": "Nach Ablauf der Frist ist eine Einladung nicht mehr gültig und der Empfänger der Einladung kann kein Konto erstellen." + "description": "Nach Ablauf der Frist ist die Einladung nicht mehr gültig und der Empfänger der Einladung kann kein Konto mehr erstellen." }, "copy": { "title": "", @@ -2011,12 +2293,12 @@ "setting": { "general": { "title": "Allgemein", - "owner": "", + "owner": "Eigentümer", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, "members": { - "title": "", + "title": "Mitglieder", "search": "", "notFound": "" }, @@ -2059,39 +2341,47 @@ } }, "crawlingAndIndexing": { - "title": "", - "warning": "", + "title": "Suche und Indexiere", + "warning": "Das Aktivieren oder Deaktivieren von Einstellungen hier wird schwerwiegende Auswirkungen haben, wie Suchmaschinen Ihre Seite suchen und indizieren. Jede Einstellung startet eine Anforderung und es ist die Aufgabe des Crawlers, diese Einstellungen zu übernehmen. Änderungen können mehrere Tage oder Wochen dauern. Einige Einstellungen können Suchmaschinenspezifisch sein.", "noIndex": { - "title": "", - "text": "" + "title": "Kein Index", + "text": "Die Webseite nicht in Suchmaschinen indizieren und in keinem Suchergebnis anzeigen" }, "noFollow": { - "title": "", - "text": "" + "title": "Keine Folgen", + "text": "Folgen Sie keine Links während der Indexierung. Deaktivieren kann dazu führen, dass Crawler versuchen, allen Links auf Homarr zu folgen." }, "noTranslate": { - "title": "", - "text": "" + "title": "Nicht Übersetzen", + "text": "Wenn die Sprache der Seite wahrscheinlich nicht zu lesen ist wird der Benutzer höchstwahrscheinlich wollen das Google einen Übersetzungslink in den Suchergebnissen zeigt" }, "noSiteLinksSearchBox": { - "title": "", - "text": "" + "title": "Kein Suchfeld für Seitenlinks", + "text": "Google baut ein Suchfeld mit den gecrawlten Links zusammen mit anderen direkten Links auf. Durch das Aktivieren dieser Option wird Google aufgefordert, dieses Feld zu deaktivieren." } }, "board": { "title": "", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Aussehen", "defaultColorScheme": { "label": "", "options": { - "light": "", - "dark": "" + "light": "Hell", + "dark": "Dunkel" } } }, @@ -2108,10 +2398,13 @@ "title": "", "status": { "idle": "", - "running": "Aktiv", + "running": "Wird ausgeführt", "error": "Fehler" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2143,7 +2436,7 @@ "label": "" }, "indexerManager": { - "label": "" + "label": "Index Manager" }, "healthMonitoring": { "label": "" @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2313,7 +2631,7 @@ }, "tab": { "user": "Benutzer", - "group": "", + "group": "Gruppen", "inherited": "" }, "field": { @@ -2321,7 +2639,7 @@ "label": "Benutzer" }, "group": { - "label": "" + "label": "Gruppe" }, "permission": { "label": "" @@ -2339,7 +2657,7 @@ "label": "" }, "integrations": { - "label": "", + "label": "Integrationen", "edit": { "label": "Bearbeiten" }, @@ -2348,7 +2666,7 @@ } }, "search-engines": { - "label": "", + "label": "Suchmaschinen", "new": { "label": "" }, @@ -2357,7 +2675,7 @@ } }, "medias": { - "label": "" + "label": "Medien" }, "apps": { "label": "", @@ -2377,7 +2695,7 @@ "security": "Sicherheit", "board": "", "groups": { - "label": "" + "label": "Gruppen" }, "invites": { "label": "Einladungen" @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2418,7 +2739,7 @@ "label": "" }, "edit": { - "label": "" + "label": "App bearbeiten" } }, "detail": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2446,7 +2770,7 @@ } }, "integration": { - "title": "" + "title": "Integrationen" } } }, @@ -2460,8 +2784,8 @@ "title": "", "option": { "colorScheme": { - "light": "", - "dark": "" + "light": "Zum hellen Design wechseln", + "dark": "Zum dunklen Design wechseln" }, "language": { "label": "", @@ -2501,11 +2825,16 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { "searchEngine": { - "title": "", + "title": "Suchmaschinen", "children": { "action": { "search": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2612,7 +2959,7 @@ "label": "" }, "manageLog": { - "label": "" + "label": "Logs anzeigen" }, "manageTask": { "label": "" @@ -2650,7 +2997,7 @@ } }, "group": { - "title": "", + "title": "Gruppen", "children": { "action": { "detail": { @@ -2684,12 +3031,12 @@ "label": "" }, "description": { - "label": "" + "label": "Beschreibung" } }, "page": { "list": { - "title": "", + "title": "Suchmaschinen", "noResults": { "title": "", "action": "" @@ -2713,11 +3060,11 @@ "title": "", "notification": { "success": { - "title": "", + "title": "Änderungen erfolgreich angewendet", "message": "" }, "error": { - "title": "", + "title": "Änderungen konnten nicht angewendet werden", "message": "" } }, @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/el.json b/packages/translation/src/lang/el.json index cdefe17f3..2c20f686a 100644 --- a/packages/translation/src/lang/el.json +++ b/packages/translation/src/lang/el.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "Εφαρμογές", + "boards": "Πίνακες", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "Ρυθμίσεις", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "Χρήστες", "name": "Χρήστης", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "Εφαρμογές", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "Εφαρμογές", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "Προηγούμενο", "next": "Επόμενο", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Προσπαθήστε ξανά", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Σύνδεση", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Επικίνδυνη Περιοχή", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -908,13 +1043,13 @@ "label": "" }, "layout": { - "label": "", + "label": "Διάταξη", "option": { "row": { - "label": "" + "label": "Οριζόντια" }, "column": { - "label": "" + "label": "Κατακόρυφα" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Σημερινοί αποκλεισμοί", "dnsQueriesToday": "Σημερινά queries", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Σημειωματάριο", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Ο περιηγητής σας δεν υποστηρίζει iframes. Παρακαλούμε ενημερώστε το πρόγραμμα περιήγησης." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "Προεπιλεγμένη προβολή" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "Εργάτες", + "queue": "Ουρά", + "statistics": "Στατιστικά" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "Στην ουρά", + "status": { + "healthy": "Υγιές", + "unhealthy": "Μη υγιές" + } + }, + "panel": { + "statistics": { + "empty": "Άδειο", + "transcodes": "Μετακωδικοποιήσεις", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "Κωδικοποιητές", + "videoContainers": "", + "videoResolutions": "Αναλύσεις" + }, + "workers": { + "empty": "Άδειο", + "table": { + "file": "Αρχείο", + "eta": "Εκτιμώμενος χρόνος αναμονής", + "progress": "Πρόοδος", + "transcode": "Μετακωδικοποίηση", + "healthCheck": "" + } + }, + "queue": { + "empty": "Άδειο", + "table": { + "file": "Αρχείο", + "size": "Μέγεθος", + "transcode": "Μετακωδικοποίηση", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Μικρό", "md": "Μεσαίο", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Οριστική διαγραφή", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Γενικά", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Πρώτη ημέρα της εβδομάδας", "accessibility": "Προσβασιμότητα" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Γενικά", - "owner": "", + "owner": "Ιδιοκτήτης", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Πίνακες", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Εμφάνιση", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Σφάλμα" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index 3ad0c7e85..897f03dc6 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "Welcome to Homarr", + "subtitle": "Let's get started with setting up your Homarr instance.", + "description": "To get started, please select how you want to set up your Homarr instance.", + "action": { + "scratch": "Start from scratch", + "importOldmarr": "Import from Homarr before 1.0" + } + }, + "import": { + "title": "Import data", + "subtitle": "You can import data from an existing Homarr instance.", + "dropzone": { + "title": "Drag the zip file here or click to browse", + "description": "The uploaded zip will be processed and you'll be able to select what you want to import" + }, + "fileInfo": { + "action": { + "change": "Change file" + } + }, + "importSettings": { + "title": "Import settings", + "description": "Configure the import behavior" + }, + "boardSelection": { + "title": "Found {count} boards", + "description": "Choose all boards with there size you want to import", + "action": { + "selectAll": "Select all", + "unselectAll": "Unselect all" + } + }, + "summary": { + "title": "Import summary", + "description": "In the below summary you can see what will be imported", + "action": { + "import": "Confirm import and continue" + }, + "entities": { + "apps": "Apps", + "boards": "Boards", + "integrations": "Integrations", + "credentialUsers": "Credential users" + } + }, + "tokenModal": { + "title": "Enter import token", + "field": { + "token": { + "label": "Token", + "description": "Enter the shown import token from your previous homarr instance" + } + }, + "notification": { + "error": { + "title": "Invalid token", + "message": "The token you entered is invalid" + } + } + } + }, + "user": { + "title": "Admin user", + "subtitle": "Specify the credentials for your administrator user.", + "notification": { + "success": { + "title": "User created", + "message": "The user was successfully created" + }, + "error": { + "title": "User creation failed" + } + } + }, + "group": { + "title": "External group", + "subtitle": "Specify the group that should be used for external users.", + "form": { + "name": { + "label": "Group name", + "description": "Name has to match admin group of external provider" + } + } + }, + "settings": { + "title": "Settings", + "subtitle": "Configure server settings." + }, + "finish": { + "title": "Finish setup", + "subtitle": "You are ready to go!", + "description": "You have successfully completed the setup process. You can now start using Homarr. Select your next action:", + "action": { + "goToBoard": "Go to {name} board", + "createBoard": "Create your first board", + "inviteUser": "Invite other users", + "docs": "Read the documentation" + } + } + }, + "backToStart": "Back to start" + }, "user": { "title": "Users", "name": "User", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "Default search engine changed successfully" + }, + "error": { + "message": "Unable to change default search engine" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -384,6 +499,7 @@ } }, "app": { + "search": "Find an app", "page": { "list": { "title": "Apps", @@ -507,6 +623,10 @@ }, "url": { "label": "Url" + }, + "attemptSearchEngineCreation": { + "label": "Create Search Engine", + "description": "Integration \"{kind}\" can be used with the search engines. Check this to automatically configure the search engine." } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "Secrets", "lastUpdated": "Last updated {date}", + "notSet": { + "label": "No value set", + "tooltip": "This required secret has not been set yet" + }, "secureNotice": "This secret cannot be retrieved after creation", "reset": { "title": "Reset secret", @@ -609,6 +733,14 @@ "password": { "label": "Password", "newLabel": "New password" + }, + "tokenId": { + "label": "Token ID", + "newLabel": "New token ID" + }, + "realm": { + "label": "Realm", + "newLabel": "New realm" } } }, @@ -678,6 +810,7 @@ "previous": "Previous", "next": "Next", "checkoutDocs": "Check out the documentation", + "checkLogs": "Check logs for more details", "tryAgain": "Try again", "loading": "Loading" }, @@ -686,6 +819,12 @@ "label": "Icon URL", "header": "Type name or objects to filter for icons... Homarr will search through {countIcons} icons for you." }, + "colorScheme": { + "options": { + "light": "Light", + "dark": "Dark" + } + }, "information": { "min": "Min", "max": "Max", @@ -733,7 +872,8 @@ "logout": "Logout", "login": "Login", "homeBoard": "Your home board", - "loggedOut": "Logged out" + "loggedOut": "Logged out", + "updateAvailable": "{countUpdates} updates available: {tag}" } }, "dangerZone": "Danger zone", @@ -765,8 +905,10 @@ "passwordRequirements": "Password does not meet the requirements", "boardAlreadyExists": "A board with this name already exists", "invalidFileType": "Invalid file type, expected {expected}", + "invalidFileName": "Invalid file name", "fileTooLarge": "File is too large, maximum size is {maxSize}", - "invalidConfiguration": "Invalid configuration" + "invalidConfiguration": "Invalid configuration", + "groupNameTaken": "Group name already taken" } } } @@ -833,6 +975,7 @@ }, "create": { "title": "Choose item to add", + "search": "Filter items", "addToBoard": "Add to board" }, "moveResize": { @@ -958,7 +1101,8 @@ "adsBlockedTodayPercentage": "Blocked today", "dnsQueriesToday": "Queries today", "domainsBeingBlocked": "Domains on blocklist" - } + }, + "domainsTooltip": "Due to multiple integrations Homarr can't calculate the exact number of domains being blocked" }, "dnsHoleControls": { "name": "DNS Hole Controls", @@ -1033,6 +1177,25 @@ } } }, + "minecraftServerStatus": { + "name": "Minecraft Server Status", + "description": "Displays the status of a Minecraft server", + "option": { + "title": { + "label": "Title" + }, + "domain": { + "label": "Server address" + }, + "isBedrockServer": { + "label": "Bedrock server" + } + }, + "status": { + "online": "Online", + "offline": "Offline" + } + }, "notebook": { "name": "Notebook", "description": "A simple notebook widget that supports markdown", @@ -1128,6 +1291,7 @@ }, "error": { "noUrl": "No iFrame URL provided", + "unsupportedProtocol": "The URL provided is using an unsupported protocol. Please use one of ({supportedProtocols})", "noBrowerSupport": "Your Browser does not support iframes. Please update your browser." } }, @@ -1255,6 +1419,12 @@ }, "fileSystem": { "label": "Show Filesystem Info" + }, + "defaultTab": { + "label": "Default tab" + }, + "sectionIndicatorRequirement": { + "label": "Section indicator requirement" } }, "popover": { @@ -1263,7 +1433,7 @@ "memory": "Memory: {memory}GiB", "memoryAvailable": "Available: {memoryAvailable}GiB ({percent}%)", "version": "Version: {version}", - "uptime": "Uptime: {days} Days, {hours} Hours, {minutes} Minutes", + "uptime": "Uptime: {months} Months, {days} Days, {hours} Hours, {minutes} Minutes", "loadAverage": "Load average:", "minute": "1 minute", "minutes": "{count} minutes", @@ -1274,6 +1444,52 @@ "memory": {}, "error": { "internalServerError": "Failed to fetch health status" + }, + "cluster": { + "summary": { + "cpu": "CPU", + "memory": "RAM" + }, + "resource": { + "node": { + "name": "Nodes" + }, + "qemu": { + "name": "VMs" + }, + "lxc": { + "name": "LXCs" + }, + "storage": { + "name": "Storage" + } + }, + "popover": { + "rightSection": { + "node": "Node", + "vmId": "VM ID", + "plugin": "Plugin" + }, + "detail": { + "cpu": "Cores", + "memory": "Memory", + "storage": "Storage", + "uptime": "Uptime", + "haState": "HA State", + "storageType": { + "local": "Local storage", + "shared": "Shared storage" + } + } + }, + "table": { + "header": { + "name": "Name", + "cpu": "CPU", + "memory": "RAM", + "node": "Node" + } + } } }, "common": { @@ -1308,9 +1524,6 @@ "description": "Click to create a new app" }, "error": { - "action": { - "logs": "Check logs for more details" - }, "noIntegration": "No integration selected", "noData": "No integration data available" }, @@ -1342,7 +1555,12 @@ "mediaServer": { "name": "Current media server streams", "description": "Show the current streams on your media servers", - "option": {} + "option": {}, + "items": { + "user": "User", + "name": "Name", + "id": "Id" + } }, "downloads": { "name": "Download Client", @@ -1528,6 +1746,65 @@ } } }, + "mediaTranscoding": { + "name": "Media transcoding", + "description": "Statistics, current queue and worker status of your media transcoding", + "option": { + "defaultView": { + "label": "Default view" + }, + "queuePageSize": { + "label": "Queue page size" + } + }, + "tab": { + "workers": "Workers", + "queue": "Queue", + "statistics": "Statistics" + }, + "currentIndex": "{start}-{end} of {total}", + "healthCheck": { + "title": "Health check", + "queued": "Queued", + "status": { + "healthy": "Healthy", + "unhealthy": "Unhealthy" + } + }, + "panel": { + "statistics": { + "empty": "Empty", + "transcodes": "Transcodes", + "transcodesCount": "Transcodes: {value}", + "healthChecksCount": "Health checks: {value}", + "filesCount": "Files: {value}", + "savedSpace": "Saved space: {value}", + "healthChecks": "Health checks", + "videoCodecs": "Codecs", + "videoContainers": "Containers", + "videoResolutions": "Resolutions" + }, + "workers": { + "empty": "Empty", + "table": { + "file": "File", + "eta": "ETA", + "progress": "Progress", + "transcode": "Transcode", + "healthCheck": "Health check" + } + }, + "queue": { + "empty": "Empty", + "table": { + "file": "File", + "size": "Size", + "transcode": "Transcode", + "healthCheck": "Health check" + } + } + } + }, "rssFeed": { "name": "RSS feeds", "description": "Monitor and display one or more generic RSS, ATOM or JSON feeds", @@ -1558,6 +1835,20 @@ }, "board": { "action": { + "duplicate": { + "title": "Duplicate board", + "message": "This will duplicate the board {name} with all its content. If widgets reference integrations, that you are not allowed to use, they will be removed.", + "notification": { + "success": { + "title": "Board duplicated", + "message": "The board was successfully duplicated" + }, + "error": { + "title": "Unable to duplicate board", + "message": "The board could not be duplicated" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1898,7 @@ }, "screenSize": { "label": "Screen size", + "description": "In versions before 1.0 three different modes existed, so you were able to choose the amount of columns for each screen size.", "option": { "sm": "Small", "md": "Medium", @@ -1803,6 +2095,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "Welcome to Homarr", + "description": "A sleek, modern dashboard that puts all of your apps and services at your fingertips.", + "link": "Create your first board", + "notice": "To make this page disappear, create a board and set it as the home board" + }, + "notFound": { + "title": "Board not found", + "description": "The board specified was either not found or you don't have access to it.", + "link": "View all boards", + "notice": "Check the link or contact an administrator if you think it should be accessible" + }, + "homeBoard": { + "title": "No home board", + "admin": { + "description": "You haven't set a home board for the server yet.", + "link": "Configure server-wide home board", + "notice": "To make this page disappear for all users, set a home board for the server" + }, + "user": { + "description": "You haven't set a home board yet.", + "link": "Configure your home board", + "notice": "To make this page disappear, specify the home board in your preferences" + }, + "anonymous": { + "description": "The server administrator hasn't set a home board yet.", + "link": "View public boards", + "notice": "To make this page disappear, ask the server administrator to set a home board for the server" + } + } } }, "management": { @@ -1838,6 +2162,7 @@ "docker": "Docker", "logs": "Logs", "api": "API", + "certificates": "Certificates", "tasks": "Tasks" } }, @@ -1890,6 +2215,16 @@ "tooltip": "This board will show as your home board" } }, + "setMobileHomeBoard": { + "label": "Set as your mobile board", + "badge": { + "label": "Mobile", + "tooltip": "This board will show as your mobile board" + } + }, + "duplicate": { + "label": "Duplicate board" + }, "delete": { "label": "Delete permanently", "confirm": { @@ -1923,7 +2258,14 @@ "title": "General", "item": { "language": "Language & Region", - "board": "Home board", + "board": { + "title": "Home board", + "type": { + "general": "General", + "mobile": "Mobile" + } + }, + "defaultSearchEngine": "Default search engine", "firstDayOfWeek": "First day of the week", "accessibility": "Accessibility" } @@ -2082,9 +2424,17 @@ "title": "Boards", "homeBoard": { "label": "Global home board", + "mobileLabel": "Global mobile board", "description": "Only public boards are available for selection" } }, + "search": { + "title": "Search", + "defaultSearchEngine": { + "label": "Global default search engine", + "description": "Integration search engines can not be selected here" + } + }, "appearance": { "title": "Appearance", "defaultColorScheme": { @@ -2112,6 +2462,9 @@ "error": "Error" }, "job": { + "minecraftServerStatus": { + "label": "Minecraft server status" + }, "iconsUpdater": { "label": "Icons Updater" }, @@ -2153,6 +2506,12 @@ }, "sessionCleanup": { "label": "Session Cleanup" + }, + "updateChecker": { + "label": "Update checker" + }, + "mediaTranscoding": { + "label": "Media transcoding" } } }, @@ -2300,7 +2659,26 @@ "message": "Something went wrong while refreshing the containers" } } + }, + "addToHomarr": { + "label": "Add to Homarr", + "notification": { + "success": { + "title": "Added to Homarr", + "message": "Selected apps have been added to Homarr" + }, + "error": { + "title": "Could not add to Homarr", + "message": "Selected apps could not be added to Homarr" + } + }, + "modal": { + "title": "Add docker container(-s) to Homarr" + } } + }, + "error": { + "internalServerError": "Failed to fetch Docker containers" } }, "permission": { @@ -2390,6 +2768,9 @@ }, "logs": { "label": "Logs" + }, + "certificates": { + "label": "Certificates" } }, "settings": { @@ -2436,6 +2817,9 @@ "homeBoard": { "label": "Set as home board" }, + "mobileBoard": { + "label": "Set as mobile board" + }, "settings": { "label": "Open settings" } @@ -2501,6 +2885,11 @@ } } }, + "media": { + "requestMovie": "Request movie", + "requestSeries": "Request series", + "openIn": "Open in {kind}" + }, "external": { "help": "Use an external search engine", "group": { @@ -2567,6 +2956,24 @@ }, "home": { "group": { + "search": { + "title": "Search", + "option": { + "other": { + "label": "Search with another search engine" + }, + "no-default": { + "label": "No default search engine", + "description": "Set a default search engine in preferences" + }, + "search": { + "label": "Search for \"{query}\" with {name}" + }, + "from-integration": { + "description": "Start typing to search" + } + } + }, "local": { "title": "Local results" } @@ -2741,6 +3148,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "Request \"{name}\"", + "table": { + "header": { + "season": "Season", + "episodes": "Episodes" + } + }, + "button": { + "send": "Send request" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "Trusted certificates", + "description": "Used by Homarr to request data from integrations.", + "noResults": { + "title": "There are no certificates yet" + }, + "expires": "Expires {when}" + } + }, + "action": { + "create": { + "label": "Add certificate", + "notification": { + "success": { + "title": "Certificate added", + "message": "The certificate was added successfully" + }, + "error": { + "title": "Failed to add certificate", + "message": "The certificate could not be added" + } + } + }, + "remove": { + "label": "Remove certificate", + "confirm": "Are you sure you want to remove the certificate?", + "notification": { + "success": { + "title": "Certificate removed", + "message": "The certificate was removed successfully" + }, + "error": { + "title": "Certificate not removed", + "message": "The certificate could not be removed" + } + } } } } diff --git a/packages/translation/src/lang/es.json b/packages/translation/src/lang/es.json index afd5fa731..977eb1190 100644 --- a/packages/translation/src/lang/es.json +++ b/packages/translation/src/lang/es.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "Bienvenido a Homarr", + "subtitle": "", + "description": "", + "action": { + "scratch": "Empezar de cero", + "importOldmarr": "Importar de Homarr antes de 1.0" + } + }, + "import": { + "title": "Importar datos", + "subtitle": "", + "dropzone": { + "title": "Arrastre el archivo zip aquí o haga clic para navegar", + "description": "El zip subido será procesado y podrás seleccionar lo que quieres importar" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "Importar ajustes", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "Aplicaciones", + "boards": "Tableros", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "Ajustes", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "Usuarios", "name": "Usuario", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "Aplicaciones", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "Aplicaciones", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "Anterior", "next": "Siguiente", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Inténtalo de nuevo", "loading": "" }, @@ -686,12 +811,18 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", "days": "", - "hours": "", - "minutes": "" + "hours": "Horas", + "minutes": "Minutos" }, "notification": { "create": { @@ -733,7 +864,8 @@ "logout": "", "login": "Iniciar sesión", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Zona de riesgo", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -908,7 +1043,7 @@ "label": "" }, "layout": { - "label": "", + "label": "Diseño", "option": { "row": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Bloqueados hoy", "dnsQueriesToday": "Consultas de hoy", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -989,13 +1125,13 @@ "enableAll": "", "disableAll": "", "setTimer": "", - "set": "", + "set": "Establecer", "enabled": "Activado", "disabled": "Desactivado", "processing": "", "disconnected": "", - "hours": "", - "minutes": "", + "hours": "Horas", + "minutes": "Minutos", "unlimited": "" } }, @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Bloc de notas", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Tu navegador no soporta iframes. Por favor, actualice tu navegador." } }, @@ -1227,15 +1383,15 @@ } }, "indexerManager": { - "name": "", + "name": "Estado del Administrador de Índices", "description": "", "option": { "openIndexerSiteInNewTab": { "label": "" } }, - "title": "", - "testAll": "", + "title": "Administrador de Índices", + "testAll": "Probar todo", "error": { "internalServerError": "" } @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1389,7 +1547,7 @@ }, "added": { "columnTitle": "", - "detailsTitle": "" + "detailsTitle": "Fecha Agregada" }, "category": { "columnTitle": "", @@ -1451,7 +1609,7 @@ }, "states": { "downloading": "Descargando", - "queued": "", + "queued": "En cola", "paused": "Pausado", "completed": "Completado", "failed": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "Vista predeterminada" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "Trabajadores", + "queue": "Cola", + "statistics": "Estadísticas" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "En cola", + "status": { + "healthy": "Saludable", + "unhealthy": "No saludable" + } + }, + "panel": { + "statistics": { + "empty": "Vacío", + "transcodes": "Transcodificaciones", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "Códecs", + "videoContainers": "Contenedores", + "videoResolutions": "Resoluciones" + }, + "workers": { + "empty": "Vacío", + "table": { + "file": "Archivo", + "eta": "Tiempo restante", + "progress": "Completado %", + "transcode": "Transcodificar", + "healthCheck": "" + } + }, + "queue": { + "empty": "Vacío", + "table": { + "file": "Archivo", + "size": "Tamaño", + "transcode": "Transcodificar", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Pequeño", "md": "Mediano", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Eliminar permanentemente", "confirm": { @@ -1923,7 +2198,14 @@ "title": "", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Primer día de la semana", "accessibility": "Accesibilidad" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "", - "owner": "", + "owner": "Propietario", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Tableros", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Apariencia", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2206,7 +2505,7 @@ } }, "docker": { - "title": "", + "title": "Contenedores", "table": { "updated": "", "search": "", @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/et.json b/packages/translation/src/lang/et.json index aa129b710..8f573559d 100644 --- a/packages/translation/src/lang/et.json +++ b/packages/translation/src/lang/et.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "", + "boards": "", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "", "name": "", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "", "next": "", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "", "dnsQueriesToday": "", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "" } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "", + "queue": "", + "statistics": "" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "", + "status": { + "healthy": "", + "unhealthy": "" + } + }, + "panel": { + "statistics": { + "empty": "", + "transcodes": "", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "" + }, + "workers": { + "empty": "", + "table": { + "file": "", + "eta": "", + "progress": "", + "transcode": "", + "healthCheck": "" + } + }, + "queue": { + "empty": "", + "table": { + "file": "", + "size": "", + "transcode": "", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "", "md": "", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "", "confirm": { @@ -1923,7 +2198,14 @@ "title": "", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "", "accessibility": "" } @@ -2081,6 +2363,14 @@ "board": { "title": "", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } @@ -2112,6 +2402,9 @@ "error": "" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/fr.json b/packages/translation/src/lang/fr.json index 821a68655..96d1cdeef 100644 --- a/packages/translation/src/lang/fr.json +++ b/packages/translation/src/lang/fr.json @@ -1,26 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "Bienvenue dans Homarr", + "subtitle": "Commençons par configurer votre instance Homarr.", + "description": "Pour commencer, veuillez selectionner comment vous souhaitez configurer votre instance Homarr.", + "action": { + "scratch": "Partir de zéro", + "importOldmarr": "Importer à partir d'Homarr avant la 1.0" + } + }, + "import": { + "title": "Importer des données", + "subtitle": "Vous pouvez importer des données depuis une instance Homarr existante.", + "dropzone": { + "title": "Déposez le fichier zip ici ou cliquez pour naviguer", + "description": "Le zip téléchargé sera traité et vous pourrez sélectionner ce que vous voulez importer" + }, + "fileInfo": { + "action": { + "change": "Changer le fichier" + } + }, + "importSettings": { + "title": "Importer des paramètres", + "description": "Configurer le comportement d'importation" + }, + "boardSelection": { + "title": "{count} tableaux trouvés", + "description": "Choisissez tous les tableaux avec la taille que vous souhaitez importer", + "action": { + "selectAll": "Tout sélectionner", + "unselectAll": "Tout désélectionner" + } + }, + "summary": { + "title": "Résumé de l'importation", + "description": "Dans le résumé ci-dessous vous pouvez voir ce qui va être importé", + "action": { + "import": "Confirmer l'importation et continuer" + }, + "entities": { + "apps": "Applications", + "boards": "Tableaux de bord", + "integrations": "Intégrations", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "Saisir le jeton d'importation", + "field": { + "token": { + "label": "Jeton", + "description": "Entrez le jeton d'importation de votre instance précédente" + } + }, + "notification": { + "error": { + "title": "Jeton non valide", + "message": "Le jeton que vous avez saisi est invalide" + } + } + } + }, + "user": { + "title": "Administrateur", + "subtitle": "Spécifiez les informations d'identification pour votre compte d'administrateur.", + "notification": { + "success": { + "title": "Utilisateur créé", + "message": "L’utilisateur a été créé avec succès" + }, + "error": { + "title": "La création de l'utilisateur a échoué" + } + } + }, + "group": { + "title": "Groupe externe", + "subtitle": "", + "form": { + "name": { + "label": "Nom du groupe", + "description": "" + } + } + }, + "settings": { + "title": "Paramètres", + "subtitle": "Configurer les paramètres du serveur." + }, + "finish": { + "title": "Terminer la configuration", + "subtitle": "Vous êtes prêt !", + "description": "Vous avez terminé avec succès le processus d'installation. Vous pouvez maintenant commencer à utiliser Homarr. Sélectionnez votre prochaine action :", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "Inviter d'autres utilisateurs", + "docs": "Lire la documentation" + } + } + }, + "backToStart": "Retour au début" + }, "user": { "title": "Utilisateurs", "name": "Utilisateur", "page": { "login": { - "title": "", - "subtitle": "" + "title": "Connectez-vous à votre compte", + "subtitle": "Bon retour parmi nous ! Veuillez entrer vos identifiants" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "Rejoindre Homarr", + "subtitle": "Bienvenue sur Homarr! Veuillez créer votre compte", + "description": "Vous avez été invité par {username}" }, "init": { - "title": "", - "subtitle": "" + "title": "Nouvelle installation Homarr", + "subtitle": "Veuillez créer l'utilisateur administrateur initial" } }, "field": { "email": { "label": "Courriel", - "verified": "" + "verified": "Vérifié" }, "username": { "label": "Nom d'utilisateur" @@ -28,18 +133,18 @@ "password": { "label": "Mot de passe", "requirement": { - "length": "", + "length": "Contient au moins 8 caractères", "lowercase": "Inclut une lettre minuscule", "uppercase": "Inclut une lettre majuscule", "number": "Inclut un nombre", - "special": "" + "special": "Contient un symbole spécial" } }, "passwordConfirm": { "label": "Confirmation du mot de passe" }, "previousPassword": { - "label": "" + "label": "Ancien mot de passe" }, "homeBoard": { "label": "" @@ -49,25 +154,25 @@ } }, "error": { - "usernameTaken": "" + "usernameTaken": "Nom d'utilisateur déjà utilisé" }, "action": { "login": { "label": "Connexion", - "labelWith": "", + "labelWith": "Se connecter avec {provider}", "notification": { "success": { - "title": "", - "message": "" + "title": "Connexion réussie", + "message": "Vous êtes maintenant connecté" }, "error": { - "title": "", + "title": "Échec de la connexion", "message": "" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "Mot de passe oublié?", + "description": "Un administrateur peut utiliser la commande suivante pour réinitialiser votre mot de passe :" } }, "register": { @@ -79,13 +184,23 @@ }, "error": { "title": "", - "message": "" + "message": "Votre compte n'a pas pu être créé" } } }, "create": "Créer un utilisateur", "changePassword": { - "label": "", + "label": "Changer le mot de passe", + "notification": { + "success": { + "message": "Mot de passe modifié avec succès" + }, + "error": { + "message": "Modification du mot de passe impossible" + } + } + }, + "changeHomeBoard": { "notification": { "success": { "message": "" @@ -95,7 +210,7 @@ } } }, - "changeHomeBoard": { + "changeDefaultSearchEngine": { "notification": { "success": { "message": "" @@ -127,29 +242,29 @@ }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Modifier l’image", "notification": { "success": { - "message": "" + "message": "L'image a été modifiée avec succès" }, "error": { - "message": "" + "message": "Impossible de modifier l'image" }, "toLarge": { - "title": "", - "message": "" + "title": "L'image est trop volumineuse", + "message": "La taille maximale de l'image est {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Retirer l'image", + "confirm": "Êtes-vous sûr de vouloir retirer cette image ?", "notification": { "success": { - "message": "" + "message": "Image retirée avec succès" }, "error": { - "message": "" + "message": "Impossible de retirer l'image" } } } @@ -157,58 +272,58 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "Profil mis à jour avec succès" }, "error": { - "message": "" + "message": "Impossible de mettre à jour le profil" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "Supprimer définitivement l'utilisateur", + "description": "Supprime cet utilisateur ainsi que ses préférences. Ne supprimera aucun tableau. L'utilisateur ne sera pas averti.", + "confirm": "Êtes-vous sûr de vouloir supprimer l'utilisateur {username} ainsi que ses préférences ?" }, "select": { - "label": "", - "notFound": "" + "label": "Sélectionner l'utilisateur", + "notFound": "Aucun utilisateur trouvé" }, "transfer": { - "label": "" + "label": "Choisir un nouveau propriétaire" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "Groupes", + "name": "Groupe", + "search": "Trouver un groupe", "field": { "name": "Nom", - "members": "" + "members": "Membres" }, "permission": { "admin": { - "title": "", + "title": "Admin", "item": { "admin": { - "label": "", - "description": "" + "label": "Administrateur", + "description": "Les membres avec cette permission ont un accès complet à toutes les fonctionnalités et paramètres" } } }, "app": { - "title": "", + "title": "Applications", "item": { "create": { - "label": "", - "description": "" + "label": "Créer une app", + "description": "Autoriser les membres à créer des apps" }, "use-all": { - "label": "", + "label": "Utiliser toutes les apps", "description": "" }, "modify-all": { - "label": "", + "label": "Modifier toutes les apps", "description": "" }, "full-all": { @@ -239,11 +354,11 @@ } }, "integration": { - "title": "", + "title": "Intégrations", "item": { "create": { - "label": "", - "description": "" + "label": "Créer des intégrations", + "description": "Autoriser les membres à créer des intégrations" }, "use-all": { "label": "", @@ -260,37 +375,37 @@ } }, "media": { - "title": "", + "title": "Médias", "item": { "upload": { - "label": "", - "description": "" + "label": "Téléverser des médias", + "description": "Autoriser les membres à téléverser des médias" }, "view-all": { - "label": "", - "description": "" + "label": "Voir tous les médias", + "description": "Autoriser les membres à voir tous les médias" }, "full-all": { - "label": "", - "description": "" + "label": "Accès complet aux médias", + "description": "Autoriser les membres à gérer et supprimer les médias" } } }, "other": { - "title": "", + "title": "Autre", "item": { "view-logs": { - "label": "", - "description": "" + "label": "Voir les logs", + "description": "Autoriser les membres à voir les logs" } } }, "search-engine": { - "title": "", + "title": "Moteurs de recherche", "item": { "create": { - "label": "", - "description": "" + "label": "Créer des moteurs de recherche", + "description": "Autoriser les membres à créer des moteurs de recherche" }, "modify-all": { "label": "", @@ -308,62 +423,62 @@ "external": "" }, "reservedNotice": { - "message": "" + "message": "Ce groupe est réservé pour l'utilisation du système et restreint certaines actions. " }, "action": { "create": { - "label": "", + "label": "Nouveau groupe", "notification": { "success": { - "message": "" + "message": "Le groupe a été créé avec succès" }, "error": { - "message": "" + "message": "Le groupe n'a pas pu être créé" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "Changer le propriétaire", + "description": "Transférer la propriété de ce groupe à un autre utilisateur.", + "confirm": "Êtes-vous sûr de vouloir transférer la propriété du groupe {name} à {username}?", "notification": { "success": { - "message": "" + "message": "Le groupe {group} a été transféré avec succès à {user}" }, "error": { - "message": "" + "message": "Impossible de transférer la propriété" } } }, "addMember": { - "label": "" + "label": "Ajouter un membre" }, "removeMember": { - "label": "", - "confirm": "" + "label": "Retirer un membre", + "confirm": "Êtes-vous sûr de vouloir retirer {user} de ce groupe ?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "Supprimer le groupe", + "description": "Une fois que vous supprimez un groupe, il n'y a pas de retour en arrière possible. Soyez certain.", + "confirm": "Êtes-vous sûr de vouloir supprimer le groupe {name}?", "notification": { "success": { - "message": "" + "message": "Groupe {name} supprimé avec succès" }, "error": { - "message": "" + "message": "Impossible de supprimer le groupe {name}" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "Permissions sauvegardées", + "message": "Les permissions ont été sauvegardées avec succès" }, "error": { - "title": "", - "message": "" + "title": "Permissions non sauvegardées", + "message": "Les permissions n'ont pas été sauvegardées" } } }, @@ -378,26 +493,27 @@ } }, "select": { - "label": "", - "notFound": "" + "label": "Sélectionner un groupe", + "notFound": "Aucun groupe trouvé" } } }, "app": { + "search": "", "page": { "list": { "title": "Applications", "noResults": { - "title": "", - "action": "" + "title": "Il n'y a pas encore d'apps", + "action": "Créer votre première app" } }, "create": { - "title": "", + "title": "Nouvelle app", "notification": { "success": { - "title": "", - "message": "" + "title": "Créé avec succès", + "message": "L'application a bien été créée" }, "error": { "title": "", @@ -413,17 +529,17 @@ "message": "" }, "error": { - "title": "", + "title": "Impossible d'appliquer les changements", "message": "" } } }, "delete": { - "title": "", - "message": "", + "title": "Supprimer l'app", + "message": "Êtes-vous sûr de vouloir supprimer l'app {name}?", "notification": { "success": { - "title": "", + "title": "Suppression effectuée avec succès", "message": "" }, "error": { @@ -438,23 +554,23 @@ "label": "Nom" }, "description": { - "label": "" + "label": "Description" }, "url": { - "label": "" + "label": "Url" } }, "action": { "select": { - "label": "", - "notFound": "" + "label": "Sélectionner l'app", + "notFound": "Aucune app trouvée" } } }, "integration": { "page": { "list": { - "title": "", + "title": "Intégrations", "search": "", "noResults": { "title": "" @@ -464,7 +580,7 @@ "title": "", "notification": { "success": { - "title": "", + "title": "Créé avec succès", "message": "" }, "error": { @@ -506,37 +622,41 @@ "label": "Nom" }, "url": { - "label": "" + "label": "Url" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { - "create": "" + "create": "Nouvelle intégration" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "Tester la connexion et créer", + "edit": "Tester la connexion et enregistrer" }, - "alertNotice": "", + "alertNotice": "Le bouton Enregistrer est activé une fois qu'une connexion est établie avec succès", "notification": { "success": { - "title": "", - "message": "" + "title": "Connexion réussie", + "message": "La connexion a été établie avec succès" }, "invalidUrl": { "title": "URL invalide", - "message": "" + "message": "L'URL est invalide." }, "secretNotDefined": { - "title": "", - "message": "" + "title": "Identifiants manquants", + "message": "Les informations d'identification n'ont pas toutes été fournies" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "Informations d'identification incorrectes.", + "message": "Les informations d'identification ne sont pas valides" }, "commonError": { - "title": "", + "title": "Échec de la connexion", "message": "" }, "badRequest": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -600,11 +724,11 @@ "kind": { "username": { "label": "Nom d'utilisateur", - "newLabel": "" + "newLabel": "Nouveau nom d'utilisateur" }, "apiKey": { - "label": "", - "newLabel": "" + "label": "Clé API", + "newLabel": "Nouvelle clé API" }, "password": { "label": "Mot de passe", @@ -624,7 +748,7 @@ "field": { "name": "Nom", "size": "Taille", - "creator": "Créé par" + "creator": "Créateur" }, "action": { "upload": { @@ -652,12 +776,12 @@ } }, "copy": { - "label": "" + "label": "Copier l'URL" } } }, "common": { - "beta": "", + "beta": "Bêta", "error": "Erreur", "action": { "add": "Ajouter", @@ -665,7 +789,7 @@ "backToOverview": "", "create": "Créer", "edit": "Modifier", - "import": "", + "import": "Importer", "insert": "Insérer", "remove": "Supprimer", "save": "Sauvegarder", @@ -674,24 +798,31 @@ "delete": "Supprimer", "discard": "", "confirm": "Confirmer", - "continue": "", + "continue": "Continuer", "previous": "Précédent", "next": "Suivant", - "checkoutDocs": "", + "checkoutDocs": "Voir la documentation", + "checkLogs": "Vérifiez les logs pour plus de détails", "tryAgain": "Réessayer", - "loading": "" + "loading": "Chargement" }, - "here": "", + "here": "ici", "iconPicker": { "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "Clair", + "dark": "Sombre" + } + }, "information": { - "min": "", - "max": "", - "days": "", + "min": "Min", + "max": "Max", + "days": "Jours", "hours": "Heures", - "minutes": "" + "minutes": "Minutes" }, "notification": { "create": { @@ -716,7 +847,7 @@ }, "multiText": { "placeholder": "", - "addLabel": "" + "addLabel": "Ajouter {value}" }, "select": { "placeholder": "", @@ -726,14 +857,15 @@ }, "userAvatar": { "menu": { - "switchToDarkMode": "", - "switchToLightMode": "", - "management": "", + "switchToDarkMode": "Activer le mode sombre", + "switchToLightMode": "Activer le mode clair", + "management": "Administration", "preferences": "Vos préférences", - "logout": "", + "logout": "Se déconnecter", "login": "Connexion", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Zone de danger", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -874,7 +1009,7 @@ }, "widget": { "app": { - "name": "", + "name": "App", "description": "", "option": { "appId": { @@ -908,13 +1043,13 @@ "label": "" }, "layout": { - "label": "", + "label": "Mise en page", "option": { "row": { - "label": "" + "label": "Horizontale" }, "column": { - "label": "" + "label": "Verticale" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Bloqué aujourd'hui", "dnsQueriesToday": "Requêtes aujourd'hui", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Bloc-notes", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Votre navigateur internet ne prend pas en charge les iframes. Merci de le mettre à jour." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "Affichage par défaut" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "Travailleurs", + "queue": "File d'attente", + "statistics": "Statistiques" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "En file d’attente", + "status": { + "healthy": "Sain", + "unhealthy": "Dysfonctionnement" + } + }, + "panel": { + "statistics": { + "empty": "Vide", + "transcodes": "Transcodeur", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "Conteneurs", + "videoResolutions": "Résolutions" + }, + "workers": { + "empty": "Vide", + "table": { + "file": "Fichier", + "eta": "", + "progress": "Progrès", + "transcode": "Transcodeur", + "healthCheck": "" + } + }, + "queue": { + "empty": "Vide", + "table": { + "file": "Fichier", + "size": "Taille", + "transcode": "Transcodeur", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Petite", "md": "Moyenne", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Supprimer définitivement", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Général", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Premier jour de la semaine", "accessibility": "Accessibilité" } @@ -1995,7 +2277,7 @@ "label": "" }, "creator": { - "label": "Créé par" + "label": "Créateur" }, "expirationDate": { "label": "Date d'expiration" @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Général", - "owner": "", + "owner": "Propriétaire", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Tableaux de bord", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Apparence", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Erreur" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2460,8 +2784,8 @@ "title": "", "option": { "colorScheme": { - "light": "", - "dark": "" + "light": "Activer le mode clair", + "dark": "Activer le mode sombre" }, "language": { "label": "", @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/he.json b/packages/translation/src/lang/he.json index c9bf4c283..c018c2c62 100644 --- a/packages/translation/src/lang/he.json +++ b/packages/translation/src/lang/he.json @@ -1,26 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "ברוכים הבאים ל- Homarr", + "subtitle": "בוא נתחיל בהגדרת ה-Homarr שלך.", + "description": "כדי להתחיל, בחר כיצד ברצונך להגדיר את ה-Homarr שלך.", + "action": { + "scratch": "התחל מאפס", + "importOldmarr": "יבוא מ-Homarr לפני 1.0" + } + }, + "import": { + "title": "ייבוא נתונים", + "subtitle": "אתה יכול לייבא נתונים מ- Homarr קיים.", + "dropzone": { + "title": "גרור את קובץ ה-zip לכאן או לחץ כדי לחפש", + "description": "ה-zip שהועלה יעובד ותוכל לבחור מה אתה רוצה לייבא" + }, + "fileInfo": { + "action": { + "change": "שנה קובץ" + } + }, + "importSettings": { + "title": "הגדרות ייבוא", + "description": "הגדר את התנהגות הייבוא" + }, + "boardSelection": { + "title": "נמצאו {count} לוחות", + "description": "בחר את כל הלוחות שברצונך לייבא", + "action": { + "selectAll": "בחר הכל", + "unselectAll": "בטל את הבחירה בכולם" + } + }, + "summary": { + "title": "סיכום ייבוא", + "description": "בסיכום למטה תוכלו לראות מה ייבא", + "action": { + "import": "אשר את הייבוא והמשך" + }, + "entities": { + "apps": "אפליקציות", + "boards": "לוחות", + "integrations": "אינטגרציות", + "credentialUsers": "משתמשים מאושרים" + } + }, + "tokenModal": { + "title": "הזן אסימון ייבוא", + "field": { + "token": { + "label": "טוקן", + "description": "הזן את אסימון הייבוא המוצג ב- Homarr הקודם שלך" + } + }, + "notification": { + "error": { + "title": "אסימון לא חוקי", + "message": "האסימון שהזנת אינו חוקי" + } + } + } + }, + "user": { + "title": "משתמש מנהל", + "subtitle": "ציין את האישורים עבור משתמש המנהל שלך.", + "notification": { + "success": { + "title": "המשתמש נוצר", + "message": "המשתמש נוצר בהצלחה" + }, + "error": { + "title": "יצירת המשתמש נכשלה" + } + } + }, + "group": { + "title": "קבוצה חיצונית", + "subtitle": "ציין את הקבוצה שבה יש להשתמש עבור משתמשים חיצוניים.", + "form": { + "name": { + "label": "שם הקבוצה", + "description": "השם צריך להתאים לקבוצת הניהול של הספק החיצוני" + } + } + }, + "settings": { + "title": "הגדרות", + "subtitle": "קבע את הגדרות השרת." + }, + "finish": { + "title": "סיים את ההגדרה", + "subtitle": "המערכת מוכנה לפעולה!", + "description": "השלמת בהצלחה את תהליך ההגדרה. כעת תוכל להתחיל להשתמש ב-Homarr. בחר את הפעולה הבאה שלך:", + "action": { + "goToBoard": "עבור ללוח {name}", + "createBoard": "צור את הלוח הראשון שלך", + "inviteUser": "הזמן משתמשים אחרים", + "docs": "קרא את הדוקומנטציה" + } + } + }, + "backToStart": "חזרה להתחלה" + }, "user": { "title": "משתמשים", "name": "משתמש", "page": { "login": { - "title": "", - "subtitle": "" + "title": "היכנס לחשבון שלך", + "subtitle": "ברוך שובך! אנא הזן את שם המשתמש והסיסמה שלך" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "הצטרף ל- Homarr", + "subtitle": "ברוכים הבאים ל- Homarr! נא ליצור את החשבון שלך", + "description": "הוזמנת על ידי {username}" }, "init": { - "title": "", - "subtitle": "" + "title": "התקנת Homarr חדשה", + "subtitle": "נא ליצור את משתמש המנהל הראשוני" } }, "field": { "email": { "label": "אימייל", - "verified": "" + "verified": "מאומת" }, "username": { "label": "שם משתמש" @@ -28,46 +133,46 @@ "password": { "label": "סיסמה", "requirement": { - "length": "", + "length": "כולל לפחות 8 תווים", "lowercase": "אפשר אותיות קטנות", "uppercase": "אפשר אותיות גדולות", "number": "אפשר מספרים", - "special": "" + "special": "כולל סמל מיוחד" } }, "passwordConfirm": { "label": "אימות סיסמא" }, "previousPassword": { - "label": "" + "label": "סיסמה קודמת" }, "homeBoard": { - "label": "" + "label": "לוח בית" }, "pingIconsEnabled": { - "label": "" + "label": "השתמש בסמלים עבור פינגים" } }, "error": { - "usernameTaken": "" + "usernameTaken": "שם המשתמש תפוס" }, "action": { "login": { "label": "התחבר/י", - "labelWith": "", + "labelWith": "התחבר עם {provider}", "notification": { "success": { - "title": "", - "message": "" + "title": "התחברת בהצלחה", + "message": "אתה כעת מחובר" }, "error": { - "title": "", - "message": "" + "title": "התחברות נכשלה", + "message": "הכניסה נכשלה" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "שכחת את הסיסמה שלך?", + "description": "מנהל מערכת יכול להשתמש בפקודה הבאה כדי לאפס את הסיסמה שלך:" } }, "register": { @@ -75,81 +180,91 @@ "notification": { "success": { "title": "החשבון נוצר", - "message": "" + "message": "אנא היכנס כדי להמשיך" }, "error": { - "title": "", - "message": "" + "title": "יצירת החשבון נכשלה", + "message": "לא ניתן ליצור את החשבון שלך" } } }, "create": "צור משתמש", "changePassword": { - "label": "", + "label": "שינוי סיסמה", "notification": { "success": { - "message": "" + "message": "הסיסמה שונתה בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן לשנות סיסמה" } } }, "changeHomeBoard": { "notification": { "success": { - "message": "" + "message": "לוח הבית השתנה בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן לשנות לוח בית" + } + } + }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "מנוע ברירת המחדל השתנה בהצלחה" + }, + "error": { + "message": "אין אפשרות לשנות מנוע חיפוש ברירת מחדל" } } }, "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "היום הראשון בשבוע השתנה בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן לשנות את היום הראשון בשבוע" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "סמלי פינג הוחלפו בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן לשנות את סמלי הפינג" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "שנה תמונה", "notification": { "success": { - "message": "" + "message": "התמונה השתנתה בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן לשנות תמונה" }, "toLarge": { - "title": "", - "message": "" + "title": "התמונה גדולה מדי", + "message": "גודל התמונה המרבי הוא {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "הסר תמונה", + "confirm": "האם אתה בטוח שברצונך להסיר את התמונה?", "notification": { "success": { - "message": "" + "message": "התמונה הוסרה בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן להסיר תמונה" } } } @@ -157,63 +272,63 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "הפרופיל עודכן בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן לעדכן את הפרופיל" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "מחק משתמש לצמיתות", + "description": "מוחק משתמש זה כולל העדפותיו. לא ימחק אף לוח. המשתמש לא יקבל הודעה.", + "confirm": "האם אתה בטוח שאתה רוצה למחוק את המשתמש {username} עם ההעדפות שלו?" }, "select": { - "label": "", - "notFound": "" + "label": "בחר משתמש", + "notFound": "לא נמצא משתמש" }, "transfer": { - "label": "" + "label": "בחר בעלים חדש" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "קבוצות", + "name": "קבוצה", + "search": "מצא קבוצה", "field": { "name": "שם", - "members": "" + "members": "חברים" }, "permission": { "admin": { "title": "מנהל מערכת", "item": { "admin": { - "label": "", - "description": "" + "label": "מנהל", + "description": "לחברים עם הרשאה זו יש גישה מלאה לכל התכונות וההגדרות" } } }, "app": { - "title": "", + "title": "אפליקציות", "item": { "create": { - "label": "", - "description": "" + "label": "יצירת אפליקציות", + "description": "מאפשר לחברים ליצור אפליקציות" }, "use-all": { - "label": "", - "description": "" + "label": "שימוש בכל האפליקציות", + "description": "מאפשר לחברים להוסיף כל אפליקציות ללוחות שלהם" }, "modify-all": { - "label": "", - "description": "" + "label": "משנה את כל האפליקציות", + "description": "מאפשר לחברים לשנות את כל האפליקציות" }, "full-all": { - "label": "", - "description": "" + "label": "גישה מלאה לאפליקציה", + "description": "מאפשר לחברים לנהל, להשתמש ולמחוק כל אפליקציה" } } }, @@ -221,214 +336,215 @@ "title": "לוחות", "item": { "create": { - "label": "", - "description": "" + "label": "יצירת לוחות", + "description": "מאפשר לחברים ליצור לוחות" }, "view-all": { - "label": "", - "description": "" + "label": "הצגת כל הלוחות", + "description": "מאפשר לחברים לצפות בכל הלוחות" }, "modify-all": { - "label": "", - "description": "" + "label": "משנה את כל הלוחות", + "description": "מאפשר לחברים לשנות את כל הלוחות (לא כולל בקרת גישה ואזור סכנה)" }, "full-all": { - "label": "", - "description": "" + "label": "גישה מלאה ללוח", + "description": "אפשר לחברים להציג, לשנות ולמחוק את כל הלוחות (כולל בקרת גישה ואזור סכנה)" } } }, "integration": { - "title": "", + "title": "אינטגרציות", "item": { "create": { - "label": "", - "description": "" + "label": "יצירת אינטגרציות", + "description": "אפשר לחברים ליצור אינטגרציות" }, "use-all": { - "label": "", - "description": "" + "label": "שימוש בכל האינטגרציות", + "description": "מאפשר לחברים להוסיף כל אינטגרציה ללוחות שלהם" }, "interact-all": { - "label": "", - "description": "" + "label": "אינטראקציה עם כל אינטגרציה", + "description": "אפשר לחברים לקיים אינטראקציה עם כל אינטגרציה" }, "full-all": { - "label": "", - "description": "" + "label": "גישת אינטגרציה מלאה", + "description": "אפשר לחברים לנהל, להשתמש ולקיים אינטראקציה עם כל אינטגרציה" } } }, "media": { - "title": "", + "title": "מדיה", "item": { "upload": { - "label": "", - "description": "" + "label": "העלה מדיה", + "description": "אפשר לחברים להעלות מדיה" }, "view-all": { - "label": "", - "description": "" + "label": "הצג את כל המדיה", + "description": "אפשר לחברים להציג את כל המדיה" }, "full-all": { - "label": "", - "description": "" + "label": "גישה מלאה למדיה", + "description": "אפשר לחברים לנהל ולמחוק כל מדיה" } } }, "other": { - "title": "", + "title": "אחר", "item": { "view-logs": { - "label": "", - "description": "" + "label": "הצג לוגים", + "description": "אפשר לחברים לצפות בלוגים" } } }, "search-engine": { - "title": "", + "title": "מנועי חיפוש", "item": { "create": { - "label": "", - "description": "" + "label": "צור מנועי חיפוש", + "description": "אפשר לחברים ליצור מנועי חיפוש" }, "modify-all": { - "label": "", - "description": "" + "label": "שנה את כל מנועי החיפוש", + "description": "אפשר לחברים לשנות את כל מנועי החיפוש" }, "full-all": { - "label": "", - "description": "" + "label": "גישה מלאה למנועי חיפוש", + "description": "אפשר לחברים לנהל ולמחוק כל מנוע חיפוש" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "חלק מהחברים הם מספקים חיצוניים ולא ניתן לנהל אותם כאן", + "external": "כל החברים הם מספקים חיצוניים ולא ניתן לנהל אותם כאן" }, "reservedNotice": { - "message": "" + "message": "קבוצה זו שמורה לשימוש במערכת ומגבילה חלק מהפעולות. " }, "action": { "create": { - "label": "", + "label": "קבוצה חדשה", "notification": { "success": { - "message": "" + "message": "הקבוצה נוצרה בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן ליצור את הקבוצה" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "העברת בעלות", + "description": "העבר את הבעלות על הקבוצה הזו למשתמש אחר.", + "confirm": "האם אתה בטוח שברצונך להעביר בעלות על הקבוצה {name} ל- {username}?", "notification": { "success": { - "message": "" + "message": "הקבוצה {group} הועברה בהצלחה ל {user}" }, "error": { - "message": "" + "message": "לא ניתן להעביר בעלות" } } }, "addMember": { - "label": "" + "label": "הוסף חבר" }, "removeMember": { - "label": "", - "confirm": "" + "label": "הסר חבר", + "confirm": "האם אתה בטוח שברצונך להסיר את {user} מהקבוצה הזו?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "מחק קבוצה", + "description": "ברגע שתמחק/י קבוצה, לא ניתן יהיה לחזור אחורה. אנא ודא/י זאת בוודאות.", + "confirm": "האם אתה בטוח שברצונך למחוק את הקבוצה {name}?", "notification": { "success": { - "message": "" + "message": "הקבוצה {name} נמחקה בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן למחוק את הקבוצה {name}" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "ההרשאות נשמרו", + "message": "ההרשאות נשמרו בהצלחה" }, "error": { - "title": "", - "message": "" + "title": "ההרשאות לא נשמרו", + "message": "ההרשאות לא נשמרו" } } }, "update": { "notification": { "success": { - "message": "" + "message": "הקבוצה {name} נשמרה בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן לשמור את הקבוצה {name}" } } }, "select": { - "label": "", - "notFound": "" + "label": "בחר קבוצה", + "notFound": "לא נמצאה קבוצה" } } }, "app": { + "search": "חיפוש אפליקציה", "page": { "list": { "title": "אפליקציות", "noResults": { - "title": "", - "action": "" + "title": "עדיין אין אפליקציות", + "action": "צור את האפליקציה הראשונה שלך" } }, "create": { - "title": "", + "title": "אפליקציה חדשה", "notification": { "success": { - "title": "", - "message": "" + "title": "היצירה הצליחה", + "message": "האפליקציה נוצרה בהצלחה" }, "error": { - "title": "", - "message": "" + "title": "היצירה נכשלה", + "message": "לא ניתן ליצור את האפליקציה" } } }, "edit": { - "title": "", + "title": "ערוך אפליקציה", "notification": { "success": { - "title": "", - "message": "" + "title": "השינויים הוחלו בהצלחה", + "message": "האפליקציה נשמרה בהצלחה" }, "error": { - "title": "", - "message": "" + "title": "לא ניתן להחיל שינויים", + "message": "לא ניתן היה לשמור את האפליקציה" } } }, "delete": { - "title": "", - "message": "", + "title": "מחק אפליקציה", + "message": "האם אתה בטוח שברצונך למחוק את האפליקציה {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "המחיקה הצליחה", + "message": "האפליקציה נמחקה בהצלחה" }, "error": { - "title": "", - "message": "" + "title": "המחיקה נכשלה", + "message": "לא ניתן למחוק את האפליקציה" } } } @@ -438,65 +554,65 @@ "label": "שם" }, "description": { - "label": "" + "label": "תיאור" }, "url": { - "label": "" + "label": "כתובת אתר" } }, "action": { "select": { - "label": "", - "notFound": "" + "label": "בחר אפליקציה", + "notFound": "לא נמצאה אפליקציה" } } }, "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "אינטגרציות", + "search": "חיפוש אינטגרציות", "noResults": { - "title": "" + "title": "עדיין אין אינטגרציות" } }, "create": { - "title": "", + "title": "אינטגרציה {name} חדשה", "notification": { "success": { - "title": "", - "message": "" + "title": "היצירה הצליחה", + "message": "האינטגרציה נוצרה בהצלחה" }, "error": { - "title": "", - "message": "" + "title": "היצירה נכשלה", + "message": "לא ניתן ליצור את האינטגרציה" } } }, "edit": { - "title": "", + "title": "ערוך אינטגרציה {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "השינויים הוחלו בהצלחה", + "message": "האינטגרציה נשמרה בהצלחה" }, "error": { - "title": "", - "message": "" + "title": "לא ניתן להחיל שינויים", + "message": "לא ניתן היה לשמור את האינטגרציה" } } }, "delete": { - "title": "", - "message": "", + "title": "מחק אינטגרציה", + "message": "האם אתה בטוח שברצונך למחוק את האינטגרציה {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "המחיקה הצליחה", + "message": "האינטגרציה נמחקה בהצלחה" }, "error": { - "title": "", - "message": "" + "title": "המחיקה נכשלה", + "message": "לא ניתן למחוק את האינטגרציה" } } } @@ -506,105 +622,113 @@ "label": "שם" }, "url": { - "label": "" + "label": "כתובת אתר" + }, + "attemptSearchEngineCreation": { + "label": "יצירת מנוע חיפוש", + "description": "אינטגרציה {kind} יכולה לשמש עם מנועי חיפוש. סמן עבור הגדרה אוטומטית של מנוע חיפוש." } }, "action": { - "create": "" + "create": "אינטגרציה חדשה" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "בדוק חיבור וצור", + "edit": "בדוק את החיבור ושמור" }, - "alertNotice": "", + "alertNotice": "הלחצן שמור מופעל לאחר יצירת חיבור מוצלח", "notification": { "success": { - "title": "", - "message": "" + "title": "החיבור הצליח", + "message": "החיבור נוצר בהצלחה" }, "invalidUrl": { "title": "קישור לא תקין", - "message": "" + "message": "כתובת האתר אינה חוקית" }, "secretNotDefined": { - "title": "", - "message": "" + "title": "חסרים פרטי התחברות", + "message": "לא סופקו כל פרטי ההתחברות" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "פרטי התחברות שגויים", + "message": "פרטי ההתחברות אינם חוקיים" }, "commonError": { - "title": "", - "message": "" + "title": "החיבור נכשל", + "message": "לא ניתן היה ליצור את החיבור" }, "badRequest": { - "title": "", - "message": "" + "title": "בקשה שגויה", + "message": "הבקשה הייתה שגויה" }, "unauthorized": { - "title": "", - "message": "" + "title": "לא מורשה", + "message": "כנראה פרטי התחברות שגויים" }, "forbidden": { - "title": "", - "message": "" + "title": "אסור", + "message": "כנראה חסרות הרשאות" }, "notFound": { - "title": "", - "message": "" + "title": "לא נמצא", + "message": "כנראה כתובת אתר או נתיב שגויים" }, "internalServerError": { - "title": "", - "message": "" + "title": "שגיאת שרת פנימית", + "message": "השרת נתקל בשגיאה" }, "serviceUnavailable": { - "title": "", - "message": "" + "title": "השירות אינו זמין", + "message": "השרת אינו זמין כרגע" }, "connectionAborted": { - "title": "", - "message": "" + "title": "החיבור הופסק", + "message": "החיבור בוטל" }, "domainNotFound": { - "title": "", - "message": "" + "title": "הדומיין לא נמצא", + "message": "לא ניתן למצוא את הדומיין" }, "connectionRefused": { - "title": "", - "message": "" + "title": "החיבור נדחה", + "message": "החיבור נדחה" }, "invalidJson": { - "title": "", - "message": "" + "title": "JSON לא חוקי", + "message": "התגובה לא הייתה JSON חוקי" }, "wrongPath": { - "title": "", - "message": "" + "title": "נתיב שגוי", + "message": "כנראה שהנתיב שגוי" } } }, "secrets": { - "title": "", - "lastUpdated": "", - "secureNotice": "", + "title": "נתוני גישה", + "lastUpdated": "עדכון אחרון {date}", + "notSet": { + "label": "לא הוגדר ערך", + "tooltip": "נתון הגישה הנדרש עדיין לא נקבע" + }, + "secureNotice": "לא ניתן לאחזר את נתון הגישה לאחר היצירה", "reset": { - "title": "", - "message": "" + "title": "איפוס נתון גישה", + "message": "האם את/ה בטוח/ה שברצונך למחוק את נתון הגישה הזה?" }, "noSecretsRequired": { - "segmentTitle": "", - "text": "" + "segmentTitle": "אין נתוני גישה", + "text": "לא נדרשים נתוני גישה לאינטגרציה זו" }, "kind": { "username": { "label": "שם משתמש", - "newLabel": "" + "newLabel": "שם משתמש חדש" }, "apiKey": { - "label": "", - "newLabel": "" + "label": "מפתח API", + "newLabel": "מפתח API חדש" }, "password": { "label": "סיסמה", @@ -613,14 +737,14 @@ } }, "permission": { - "use": "", - "interact": "", - "full": "" + "use": "בחר אינטגרציות בפריטים", + "interact": "אינטראקציה עם אינטגרציות", + "full": "גישת אינטגרציה מלאה" } }, "media": { - "plural": "", - "search": "", + "plural": "מדיה", + "search": "מצא מדיה", "field": { "name": "שם", "size": "גודל", @@ -628,119 +752,127 @@ }, "action": { "upload": { - "label": "", - "file": "", + "label": "העלה מדיה", + "file": "בחר קובץ", "notification": { "success": { - "message": "" + "message": "המדיה הועלתה בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן היה להעלות את המדיה" } } }, "delete": { - "label": "", - "description": "", + "label": "מחק מדיה", + "description": "האם אתה בטוח שברצונך למחוק את המדיה ?", "notification": { "success": { - "message": "" + "message": "המדיה נמחקה בהצלחה" }, "error": { - "message": "" + "message": "לא ניתן למחוק את המדיה" } } }, "copy": { - "label": "" + "label": "העתק קישור" } } }, "common": { - "beta": "", + "beta": "בטא", "error": "שגיאה", "action": { "add": "הוסף", "apply": "החל", - "backToOverview": "", + "backToOverview": "חזרה לסקירה כללית", "create": "צור", "edit": "עריכה", - "import": "", + "import": "ייבוא", "insert": "הוספה", "remove": "הסר", "save": "שמור", "saveChanges": "שמור שינויים", "cancel": "בטל", "delete": "מחיקה", - "discard": "", + "discard": "ביטול", "confirm": "לאשר", - "continue": "", + "continue": "המשך", "previous": "הקודם", "next": "הבא", - "checkoutDocs": "", + "checkoutDocs": "בדוק את התיעוד", + "checkLogs": "בדוק לוגים לפרטים נוספים", "tryAgain": "נא לנסות שוב", - "loading": "" + "loading": "טוען" }, - "here": "", + "here": "כאן", "iconPicker": { - "label": "", - "header": "" + "label": "קישור של הסמל", + "header": "הקלד שם או אובייקטים לסינון עבור אייקונים... Homarr יחפש עבורך סמלים של {countIcons} ." + }, + "colorScheme": { + "options": { + "light": "בהיר", + "dark": "כהה" + } }, "information": { - "min": "", - "max": "", - "days": "", + "min": "מינימום", + "max": "מקסימום", + "days": "ימים", "hours": "שעות", "minutes": "דקות" }, "notification": { "create": { - "success": "", - "error": "" + "success": "היצירה הצליחה", + "error": "היצירה נכשלה" }, "delete": { - "success": "", - "error": "" + "success": "המחיקה הצליחה", + "error": "המחיקה נכשלה" }, "update": { - "success": "", - "error": "" + "success": "השינויים הוחלו בהצלחה", + "error": "לא ניתן להחיל שינויים" }, "transfer": { - "success": "", - "error": "" + "success": "הועבר בהצלחה", + "error": "ההעברה נכשלה" } }, "multiSelect": { - "placeholder": "" + "placeholder": "בחר ערך אחד או יותר" }, "multiText": { - "placeholder": "", - "addLabel": "" + "placeholder": "הוסף עוד ערכים", + "addLabel": "הוסף {value}" }, "select": { - "placeholder": "", + "placeholder": "בחר ערך", "badge": { - "recommended": "" + "recommended": "מומלץ" } }, "userAvatar": { "menu": { - "switchToDarkMode": "", - "switchToLightMode": "", - "management": "", + "switchToDarkMode": "עבור למצב כהה", + "switchToLightMode": "עבור למצב בהיר", + "management": "ניהול", "preferences": "העדפות שלך", - "logout": "", + "logout": "התנתק/י", "login": "התחבר/י", - "homeBoard": "", - "loggedOut": "" + "homeBoard": "לוח הבית שלך", + "loggedOut": "נותקת מהמערכת", + "updateAvailable": "{countUpdates} עדכונים זמינים: {tag}" } }, "dangerZone": "אזור מסוכן", "noResults": "לא נמצאו תוצאות", "preview": { - "show": "", - "hide": "" + "show": "הצג תצוגה מקדימה", + "hide": "הסתר תצוגה המקדימה" }, "zod": { "errors": { @@ -750,7 +882,7 @@ "startsWith": "שדה זה חייב להתחיל עם {startsWith}", "endsWith": "שדה זה חייב להסתיים עם {endsWith}", "includes": "שדה זה חייב להכיל {includes}", - "invalidEmail": "" + "invalidEmail": "שדה זה חייב להיות דוא\"ל חוקי" }, "tooSmall": { "string": "שדה זה חייב להיות באורך של {minimum} תווים לפחות", @@ -761,12 +893,14 @@ "number": "שדה זה חייב להיות קטן או שווה ל {maximum}" }, "custom": { - "passwordsDoNotMatch": "", - "passwordRequirements": "", - "boardAlreadyExists": "", - "invalidFileType": "", - "fileTooLarge": "", - "invalidConfiguration": "" + "passwordsDoNotMatch": "סיסמאות לא תואמות", + "passwordRequirements": "הסיסמה אינה עומדת בדרישות", + "boardAlreadyExists": "לוח בשם זה כבר קיים", + "invalidFileType": "סוג קובץ לא חוקי, צפוי {expected}", + "invalidFileName": "", + "fileTooLarge": "הקובץ גדול מדי, הגודל המרבי הוא {maxSize}", + "invalidConfiguration": "תצורה לא חוקית", + "groupNameTaken": "שם הקבוצה כבר תפוס" } } } @@ -774,12 +908,12 @@ "section": { "dynamic": { "action": { - "create": "", - "remove": "" + "create": "מדור דינמי חדש", + "remove": "הסר קטע דינמי" }, "remove": { - "title": "", - "message": "" + "title": "הסר קטע דינמי", + "message": "האם אתה בטוח שברצונך להסיר את הקטע הדינמי הזה? פריטים יועברו לאותו מיקום במדור האב." } }, "category": { @@ -789,29 +923,29 @@ } }, "action": { - "create": "", - "edit": "", - "remove": "", + "create": "קטגוריה חדשה", + "edit": "שנה את שם הקטגוריה", + "remove": "הסר קטגוריה", "moveUp": "הזזה למעלה", "moveDown": "הזזה למטה", - "createAbove": "", - "createBelow": "" + "createAbove": "קטגוריה חדשה למעלה", + "createBelow": "קטגוריה חדשה למטה" }, "create": { - "title": "", - "submit": "" + "title": "קטגוריה חדשה", + "submit": "הוסף קטגוריה" }, "remove": { - "title": "", - "message": "" + "title": "הסר קטגוריה", + "message": "האם אתה בטוח שברצונך להסיר את הקטגוריה {name}?" }, "edit": { - "title": "", - "submit": "" + "title": "שנה את שם הקטגוריה", + "submit": "שנה את שם הקטגוריה" }, "menu": { "label": { - "create": "", + "create": "קטגוריה חדשה", "changePosition": "שנה מיקום" } } @@ -819,12 +953,12 @@ }, "item": { "action": { - "create": "", - "import": "", - "edit": "", - "moveResize": "", - "duplicate": "", - "remove": "" + "create": "פריט חדש", + "import": "ייבוא פריט", + "edit": "ערוך פריט", + "moveResize": "הזז/שנה גודל פריט", + "duplicate": "שכפול פריט", + "remove": "הסרת פריט" }, "menu": { "label": { @@ -832,11 +966,12 @@ } }, "create": { - "title": "", - "addToBoard": "" + "title": "בחירת פריט להוספה", + "search": "סנן פריטים", + "addToBoard": "הוספה ללוח" }, "moveResize": { - "title": "", + "title": "הזז/שנה גודל פריט", "field": { "width": { "label": "רוחב" @@ -845,91 +980,91 @@ "label": "גובה" }, "xOffset": { - "label": "" + "label": "היסט X" }, "yOffset": { - "label": "" + "label": "היסט Y" } } }, "edit": { - "title": "", + "title": "ערוך פריט", "advancedOptions": { - "label": "", - "title": "" + "label": "אפשרויות מתקדמות", + "title": "אפשרויות פריט מתקדמות" }, "field": { "integrations": { - "label": "" + "label": "אינטגרציות" }, "customCssClasses": { - "label": "" + "label": "מחלקות עיצוב מותאמות אישית" } } }, "remove": { - "title": "", - "message": "" + "title": "הסרת פריט", + "message": "האם אתה בטוח שברצונך להסיר פריט זה?" } }, "widget": { "app": { - "name": "", - "description": "", + "name": "אפליקציה", + "description": "הטמעת אפליקציה בלוח.", "option": { "appId": { - "label": "" + "label": "בחר אפליקציה" }, "openInNewTab": { "label": "פתיחה בכרטיסיה חדשה" }, "showTitle": { - "label": "" + "label": "הצג את שם האפליקציה" }, "showDescriptionTooltip": { - "label": "" + "label": "הצג תיאור" }, "pingEnabled": { - "label": "" + "label": "אפשר פינג פשוט" } }, "error": { "notFound": { - "label": "", - "tooltip": "" + "label": "אין אפליקציה", + "tooltip": "לא נבחרה אפליקציה חוקית" } } }, "bookmarks": { - "name": "", - "description": "", + "name": "סימניות", + "description": "מציג קישורי אפליקציות מרובים", "option": { "title": { - "label": "" + "label": "כותרת" }, "layout": { - "label": "", + "label": "פריסה", "option": { "row": { - "label": "" + "label": "אופקי" }, "column": { - "label": "" + "label": "אנכי" }, "grid": { - "label": "" + "label": "רשת" } } }, "items": { - "label": "", - "add": "" + "label": "סימניות", + "add": "הוסף סימניה" } } }, "dnsHoleSummary": { - "name": "", - "description": "", + "name": "סיכום חור אבטחה DNS", + "description": "מציג את הסיכום חור אבטחת DNS שלך", "option": { "layout": { "label": "פריסה", @@ -941,27 +1076,28 @@ "label": "אנכי" }, "grid": { - "label": "" + "label": "רשת" } } }, "usePiHoleColors": { - "label": "" + "label": "השתמש בצבעי Pi-Hole" } }, "error": { - "internalServerError": "", - "integrationsDisconnected": "" + "internalServerError": "אחזור סיכום החור אבטחת DNS נכשל", + "integrationsDisconnected": "אין נתונים זמינים, כל האינטגרציות מנותקות" }, "data": { "adsBlockedToday": "נחסמו היום", "adsBlockedTodayPercentage": "נחסמו היום", "dnsQueriesToday": "שאילתות היום", - "domainsBeingBlocked": "" - } + "domainsBeingBlocked": "דומיינים ברשימת החסימה" + }, + "domainsTooltip": "בגלל ריבוי אינטגרציות Homarr לא יכול לחשב במדיוק את כמות הדומיינים שנחסמו" }, "dnsHoleControls": { - "name": "", + "name": "בקרות חור אבטחת DNS", "description": "שלוט ב-PiHole או ב-AdGuard מלוח המחוונים שלך", "option": { "layout": { @@ -974,68 +1110,87 @@ "label": "אנכי" }, "grid": { - "label": "" + "label": "רשת" } } }, "showToggleAllButtons": { - "label": "" + "label": "הצג את כל הלחצנים" } }, "error": { - "internalServerError": "" + "internalServerError": "השליטה בחור אבטחת DNS נכשלה" }, "controls": { - "enableAll": "", - "disableAll": "", - "setTimer": "", + "enableAll": "אפשר הכל", + "disableAll": "השבת הכל", + "setTimer": "הגדר טיימר", "set": "הגדר", "enabled": "מאופשר", "disabled": "מושבת", - "processing": "", - "disconnected": "", + "processing": "מעבד", + "disconnected": "מנותק", "hours": "שעות", "minutes": "דקות", - "unlimited": "" + "unlimited": "השאר ריק עבור ללא הגבלה" } }, "clock": { - "name": "", + "name": "תאריך ושעה", "description": "מציג את התאריך והשעה הנוכחיים.", "option": { "customTitleToggle": { - "label": "", - "description": "" + "label": "תצוגת כותרת/עיר מותאמת אישית", + "description": "הצג כותרת מותאמת אישית או שם העיר/המדינה על גבי השעון." }, "customTitle": { - "label": "" + "label": "כותרת" }, "is24HourFormat": { - "label": "", - "description": "" + "label": "פורמט 24 שעות", + "description": "השתמש בפורמט של 24 שעות במקום בפורמט של 12 שעות" }, "showSeconds": { - "label": "" + "label": "הצג שניות" }, "useCustomTimezone": { - "label": "" + "label": "השתמש באזור זמן קבוע" }, "timezone": { "label": "אזור זמן", - "description": "" + "description": "בחר את אזור הזמן בהתאם לתקן IANA" }, "showDate": { - "label": "" + "label": "הצג את התאריך" }, "dateFormat": { - "label": "", - "description": "" + "label": "פורמט תאריך", + "description": "איך צריך להיראות התאריך" } } }, + "minecraftServerStatus": { + "name": "סטטוס שרת מיינקראפט", + "description": "מציג את סטטוס שרת מיינקראפט", + "option": { + "title": { + "label": "כותרת" + }, + "domain": { + "label": "כתובת השרת" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "מקוון", + "offline": "לא מקוון" + } + }, "notebook": { "name": "פנקס רשימות", - "description": "", + "description": "ווידג'ט פשוט של מחברת התומך ב-markdown", "option": { "showToolbar": { "label": "הצג את סרגל הכלים לסיוע כתיבת סימון" @@ -1095,7 +1250,7 @@ } }, "iframe": { - "name": "", + "name": "iFrame", "description": "הטמע כל תוכן מהאינטרנט. חלק מהאתרים עשויים להגביל את הגישה.", "option": { "embedUrl": { @@ -1127,31 +1282,32 @@ } }, "error": { - "noUrl": "", + "noUrl": "לא סופק קישור של iFrame", + "unsupportedProtocol": "כתובת הרשת שסופקה בפרוטוקול שגוי. בבקשה להשתמש באחד מ- {supportedProtocols}", "noBrowerSupport": "הדפדפן שלך אינו תומך ב-iframes. נא עדכן את הדפדפן שלך." } }, "smartHome-entityState": { - "name": "", - "description": "", + "name": "מצב ישות", + "description": "הצג את המצב של ישות והחלף אותו באופן אופציונלי", "option": { "entityId": { "label": "מזהה ישות" }, "displayName": { - "label": "" + "label": "שם תצוגה" }, "entityUnit": { - "label": "" + "label": "יחידת ישות" }, "clickable": { - "label": "" + "label": "ניתן ללחיצה" } } }, "smartHome-executeAutomation": { - "name": "", - "description": "", + "name": "הפעל אוטומציה", + "description": "הפעל אוטומציה בלחיצה אחת", "option": { "displayName": { "label": "הצג שם" @@ -1161,26 +1317,26 @@ } }, "spotlightAction": { - "run": "" + "run": "הפעל {name}" } }, "calendar": { "name": "לוח שנה", - "description": "", + "description": "הצג אירועים מהאינטגרציות שלך בתצוגת לוח שנה בתוך פרק זמן יחסי מסוים", "option": { "releaseType": { "label": "סוג שחרור של Radarr", "options": { - "inCinemas": "", - "digitalRelease": "", - "physicalRelease": "" + "inCinemas": "בבתי קולנוע", + "digitalRelease": "שחרור דיגיטלי", + "physicalRelease": "שחרור פיזי" } }, "filterPastMonths": { - "label": "" + "label": "התחל מ" }, "filterFutureMonths": { - "label": "" + "label": "סיים ב" } } }, @@ -1189,24 +1345,24 @@ "description": "מציג את מידע מזג האוויר הנוכחי של מיקום מוגדר.", "option": { "isFormatFahrenheit": { - "label": "" + "label": "טמפרטורה בפרנהייט" }, "location": { "label": "מיקום מזג האוויר" }, "showCity": { - "label": "" + "label": "הצג עיר" }, "hasForecast": { - "label": "" + "label": "הצג תחזית" }, "forecastDayCount": { - "label": "", - "description": "" + "label": "כמות ימי התחזית", + "description": "כאשר הווידג'ט אינו רחב מספיק, פחות ימים מוצגים" }, "dateFormat": { - "label": "", - "description": "" + "label": "פורמט תאריך", + "description": "איך צריך להיראות התאריך" } }, "kind": { @@ -1228,16 +1384,16 @@ }, "indexerManager": { "name": "סטטוס מנהל אינדקס", - "description": "", + "description": "מצב האינדקסים שלך", "option": { "openIndexerSiteInNewTab": { - "label": "" + "label": "פתח את אתר האינדקס בכרטיסייה חדשה" } }, "title": "מנהל אינדקס", "testAll": "בדוק הכל", "error": { - "internalServerError": "" + "internalServerError": "נכשל באחזור סטטוס האינדקסים" } }, "healthMonitoring": { @@ -1258,41 +1414,41 @@ } }, "popover": { - "information": "", - "processor": "", - "memory": "", - "memoryAvailable": "", - "version": "", - "uptime": "", - "loadAverage": "", - "minute": "", - "minutes": "", - "used": "", + "information": "מידע", + "processor": "מעבד: {cpuModelName}", + "memory": "זיכרון: {memory}GiB", + "memoryAvailable": "זמין: {memoryAvailable}GiB ({percent}%)", + "version": "גרסה: {version}", + "uptime": "זמן פעילות: {months} חודשים, {days} ימים, {hours} שעות, {minutes} דקות", + "loadAverage": "ממוצע עומס:", + "minute": "דקה אחת", + "minutes": "{count} דקות", + "used": "בשימוש", "available": "זמין", - "lastSeen": "" + "lastSeen": "עדכון סטטוס אחרון: {lastSeen}" }, "memory": {}, "error": { - "internalServerError": "" + "internalServerError": "נכשל בעדכון סטטוס בריאות המערכת" } }, "common": { "location": { - "query": "", - "latitude": "", - "longitude": "", - "disabledTooltip": "", - "unknownLocation": "", + "query": "עיר / מיקוד", + "latitude": "קו רוחב", + "longitude": "קו אורך", + "disabledTooltip": "אנא הזן עיר או מיקוד", + "unknownLocation": "מיקום לא ידוע", "search": "חיפוש", "table": { "header": { - "city": "", - "country": "", - "coordinates": "", - "population": "" + "city": "עיר", + "country": "מדינה", + "coordinates": "קואורדינטות", + "population": "אוכלוסיה" }, "action": { - "select": "" + "select": "בחר {city}, {countryCode}" }, "population": { "fallback": "לא ידוע" @@ -1300,19 +1456,16 @@ } }, "integration": { - "noData": "", - "description": "" + "noData": "לא נמצא אינטגרציה", + "description": "לחץ על כדי ליצור אינטגרציה חדשה" }, "app": { - "noData": "", - "description": "" + "noData": "לא נמצאה אפליקציה", + "description": "לחץ על כדי ליצור אפליקציה חדשה" }, "error": { - "action": { - "logs": "" - }, - "noIntegration": "", - "noData": "" + "noIntegration": "לא נבחרה אינטגרציה", + "noData": "אין נתוני אינטגרציה זמינים" }, "option": {} }, @@ -1325,128 +1478,133 @@ }, "hasAutoPlay": { "label": "הפעלה אוטומטית", - "description": "" + "description": "הפעלה אוטומטית פועלת רק כשהיא מושתקת בגלל הגבלות הדפדפן" }, "isMuted": { - "label": "" + "label": "מושתק" }, "hasControls": { - "label": "" + "label": "הצג פקדים" } }, "error": { - "noUrl": "", - "forYoutubeUseIframe": "" + "noUrl": "לא סופק קישור של סרטון", + "forYoutubeUseIframe": "עבור סרטוני YouTube השתמש באפשרות iframe" } }, "mediaServer": { - "name": "", - "description": "", - "option": {} + "name": "זרמי שרת מדיה נוכחיים", + "description": "הצג את הזרמים הנוכחיים בשרתי המדיה שלך", + "option": {}, + "items": { + "user": "משתמש", + "name": "שם", + "id": "מזהה" + } }, "downloads": { - "name": "", - "description": "", + "name": "הורדת לקוח", + "description": "מאפשר לך להציג ולנהל את ההורדות שלך הן מלקוחות Torrent והן מלקוחות Usenet.", "option": { "columns": { - "label": "" + "label": "עמודות להצגה" }, "enableRowSorting": { - "label": "" + "label": "אפשר מיון פריטים" }, "defaultSort": { - "label": "" + "label": "עמודה המשמשת למיון כברירת מחדל" }, "descendingDefaultSort": { - "label": "" + "label": "מיון הפוך" }, "showCompletedUsenet": { - "label": "" + "label": "הצג ערכי usenet שסומנו כהשלמה" }, "showCompletedTorrent": { - "label": "" + "label": "הצג ערכי טורנט שסומנו כהשלמה" }, "activeTorrentThreshold": { - "label": "" + "label": "הסתר טורנט שהושלם מתחת לסף הזה (בקיB/s)" }, "categoryFilter": { - "label": "" + "label": "קטגוריות/תוויות לסינון" }, "filterIsWhitelist": { - "label": "" + "label": "סנן כרשימת היתרים" }, "applyFilterToRatio": { - "label": "" + "label": "השתמש במסנן כדי לחשב יחס" } }, "errors": { - "noColumns": "", - "noCommunications": "" + "noColumns": "בחר עמודות בפריטים", + "noCommunications": "לא ניתן לטעון נתונים מהאינטגרציה" }, "items": { "actions": { - "columnTitle": "" + "columnTitle": "פקדים" }, "added": { - "columnTitle": "", + "columnTitle": "נוסף", "detailsTitle": "נוסף בתאריך" }, "category": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "תוספות", + "detailsTitle": "קטגוריות (או מידע נוסף)" }, "downSpeed": { "columnTitle": "הורדה", "detailsTitle": "מהירות הורדה" }, "index": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "#", + "detailsTitle": "מדד נוכחי בתוך הלקוח" }, "id": { - "columnTitle": "" + "columnTitle": "מזהה" }, "integration": { "columnTitle": "אינטגרציה" }, "name": { - "columnTitle": "" + "columnTitle": "שם המשימה" }, "progress": { "columnTitle": "התקדמות", - "detailsTitle": "" + "detailsTitle": "התקדמות ההורדה" }, "ratio": { "columnTitle": "יחס", - "detailsTitle": "" + "detailsTitle": "יחס טורנט (התקבל/נשלח)" }, "received": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "סך הכל הורדה", + "detailsTitle": "הורדה כוללת" }, "sent": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "סך הכל העלאה", + "detailsTitle": "העלאה כוללת" }, "size": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "גודל קובץ", + "detailsTitle": "גודל כולל של בחירה/קבצים" }, "state": { "columnTitle": "מצב", - "detailsTitle": "" + "detailsTitle": "מצב המשימה" }, "time": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "זמן סיום", + "detailsTitle": "זמן מאז/עד סיום" }, "type": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "סוּג", + "detailsTitle": "סוג לקוח הורדה" }, "upSpeed": { "columnTitle": "העלאה", - "detailsTitle": "" + "detailsTitle": "קצב העלאה" } }, "states": { @@ -1454,38 +1612,38 @@ "queued": "בתור", "paused": "מושהה", "completed": "הושלם", - "failed": "", - "processing": "", - "leeching": "", - "stalled": "", + "failed": "נכשל", + "processing": "מעבד", + "leeching": "בשיתוף", + "stalled": "נתקע", "unknown": "לא ידוע", - "seeding": "" + "seeding": "זריעה" }, "actions": { "clients": { - "modalTitle": "", - "pause": "", - "resume": "" + "modalTitle": "רשימת לקוחות הורדה", + "pause": "השהה את כל הלקוחות/פריטים", + "resume": "המשך כל הלקוחות/פריטים" }, "client": { - "pause": "", - "resume": "" + "pause": "השהה לקוח", + "resume": "המשך לקוח" }, "item": { - "pause": "", - "resume": "", + "pause": "השהה פריט", + "resume": "המשך פריט", "delete": { - "title": "", - "modalTitle": "", - "entry": "", - "entryAndFiles": "" + "title": "מחק פריט", + "modalTitle": "האם את/ה בטוח/ה שברצונך למחוק את העבודה הזו?", + "entry": "מחיקת רשומה", + "entryAndFiles": "מחיקת רשומה וקבצים" } } }, - "globalRatio": "" + "globalRatio": "יחס גלובלי" }, "mediaRequests-requestList": { - "name": "", + "name": "רשימת בקשות מדיה", "description": "ראה רשימה של כל בקשות המדיה ממופע Overseerr או Jellyseerr שלך", "option": { "linksTargetNewTab": { @@ -1493,21 +1651,21 @@ } }, "pending": { - "approve": "", - "approving": "", - "decline": "" + "approve": "אשר בקשה", + "approving": "מאשר את הבקשה...", + "decline": "דחה בקשה" }, "availability": { "unknown": "לא ידוע", - "pending": "", - "processing": "", + "pending": "בהמתנה", + "processing": "מעבד", "partiallyAvailable": "חלקי", "available": "זמין" }, - "toBeDetermined": "" + "toBeDetermined": "ייקבע בהמשך" }, "mediaRequests-requestStats": { - "name": "", + "name": "מצב בקשות מדיה", "description": "סטטיסטיקה לגבי בקשות המדיה", "option": {}, "titles": { @@ -1515,98 +1673,172 @@ "main": "סטטיסטיקות מדיה", "approved": "כבר אושר", "pending": "ממתין לאישור", - "processing": "", - "declined": "", - "available": "", + "processing": "בעיבוד", + "declined": "נדחה כבר", + "available": "כבר זמין", "tv": "בקשות סדרות", "movie": "בקשות סרטים", "total": "סך הכל" }, "users": { "main": "משתמשים מובילים", - "requests": "" + "requests": "בקשות" + } + } + }, + "mediaTranscoding": { + "name": "המרת קידוד מדיה", + "description": "סטטיסטיקה, תור נוכחי וסטטוס עיבוד של המרת המדיה שלך", + "option": { + "defaultView": { + "label": "תצוגת ברירת מחדל" + }, + "queuePageSize": { + "label": "גודל העמוד בתור" + } + }, + "tab": { + "workers": "עובדים", + "queue": "תור", + "statistics": "סטָטִיסטִיקָה" + }, + "currentIndex": "{start}-{end} מתוך {total}", + "healthCheck": { + "title": "בדיקת תקינות", + "queued": "בתור", + "status": { + "healthy": "בָּרִיא", + "unhealthy": "לא בריא" + } + }, + "panel": { + "statistics": { + "empty": "ריק", + "transcodes": "קידודים", + "transcodesCount": "קידודים: {value}", + "healthChecksCount": "בדיקות בריאות: {value}", + "filesCount": "קבצים: {value}", + "savedSpace": "שטח שמור: {value}", + "healthChecks": "בדיקות בריאות", + "videoCodecs": "קודקים", + "videoContainers": "מיכלים", + "videoResolutions": "רזולוציות" + }, + "workers": { + "empty": "ריק", + "table": { + "file": "קוֹבֶץ", + "eta": "זמן סיום משוער", + "progress": "התקדמות", + "transcode": "קידוד", + "healthCheck": "בדיקת תקינות" + } + }, + "queue": { + "empty": "ריק", + "table": { + "file": "קוֹבֶץ", + "size": "גודל", + "transcode": "קידוד", + "healthCheck": "בדיקת תקינות" + } } } }, "rssFeed": { - "name": "", - "description": "", + "name": "הזנות RSS", + "description": "מעקב והצג עדכוני RSS, ATOM או JSON גנרי אחד או יותר", "option": { "feedUrls": { - "label": "" + "label": "כתובות אתרים של הזנה" }, "enableRtl": { - "label": "" + "label": "אפשר RTL" }, "textLinesClamp": { - "label": "" + "label": "חיתוך שורות טקסט" }, "maximumAmountPosts": { - "label": "" + "label": "הגבלת כמות הודעות" } } } }, "widgetPreview": { "toggle": { - "enabled": "", - "disabled": "" + "enabled": "מצב עריכה מופעל", + "disabled": "מצב עריכה מושבת" }, "dimensions": { - "title": "" + "title": "שנה מידות" } }, "board": { "action": { + "duplicate": { + "title": "שכפול לוח", + "message": "פעולה זו תשכפל את הלוח {name} עם כל התוכן שלו. אם ווידג'טים מתייחסים לאינטגרציות שאינך מורשה להשתמש בהן, הם יוסרו.", + "notification": { + "success": { + "title": "הלוח שוכפל", + "message": "הלוח שוכפל בהצלחה" + }, + "error": { + "title": "לא ניתן לשכפל את הלוח", + "message": "לא ניתן לשכפל את הלוח" + } + } + }, "edit": { "notification": { "success": { - "title": "", - "message": "" + "title": "השינויים הוחלו בהצלחה", + "message": "הלוח נשמר בהצלחה" }, "error": { - "title": "", - "message": "" + "title": "לא ניתן להחיל שינויים", + "message": "לא ניתן היה לשמור את הלוח" } }, "confirmLeave": { - "title": "", - "message": "" + "title": "שינויים שלא נשמרו", + "message": "יש לך שינויים שלא נשמרו, האם אתה בטוח שברצונך לעזוב?" } }, "oldImport": { - "label": "", + "label": "יבוא מ- homarr לפני 1.0.0", "notification": { "success": { - "title": "", - "message": "" + "title": "הייבוא הצליח", + "message": "הלוח יובא בהצלחה" }, "error": { - "title": "", - "message": "" + "title": "הייבוא נכשל", + "message": "לא ניתן לייבא את הלוח, בדוק את לוגים לפרטים נוספים" } }, "form": { "file": { - "label": "", - "invalidError": "" + "label": "בחר קובץ JSON", + "invalidError": "קובץ תצורה לא חוקי" }, "apps": { "label": "אפליקציות", "avoidDuplicates": { - "label": "", - "description": "" + "label": "הימנע מכפילויות", + "description": "מתעלם מאפליקציות שבהן כבר קיימת אפליקציה עם אותה כתובת רשת" }, "onlyImportApps": { - "label": "", - "description": "" + "label": "ייבוא רק אפליקציות", + "description": "רק מוסיף את האפליקציות, יש ליצור מחדש את הלוח באופן ידני" } }, "name": { - "label": "" + "label": "שם הלוח" }, "screenSize": { - "label": "", + "label": "גודל מסך", + "description": "בגרסאות שלפני 1.0 היו קיימים שלושה מצבים שונים, כך שניתן היה לבחור את כמות העמודות עבור כל גודל מסך.", "option": { "sm": "קטן", "md": "בינוני", @@ -1614,16 +1846,16 @@ } }, "sidebarBehavior": { - "label": "", - "description": "", + "label": "התנהגות סרגל הצד", + "description": "סרגלי צד הוסרו ב- 1.0, אתה יכול לבחור מה צריך לקרות עם הפריטים שבתוכם.", "option": { "lastSection": { - "label": "", - "description": "" + "label": "החלק האחרון", + "description": "סרגל צד יוצג מתחת לקטע האחרון" }, "removeItems": { - "label": "", - "description": "" + "label": "הסרת פריטים", + "description": "פריטים הכלולים בסרגל הצד יוסרו" } } } @@ -1632,51 +1864,51 @@ }, "field": { "pageTitle": { - "label": "" + "label": "כותרת העמוד" }, "metaTitle": { - "label": "" + "label": "כותרת מטא" }, "logoImageUrl": { - "label": "" + "label": "כתובת אתר של תמונת לוגו" }, "faviconImageUrl": { - "label": "" + "label": "כתובת אתר של תמונת Favicon" }, "backgroundImageUrl": { - "label": "" + "label": "כתובת אתר של תמונת רקע" }, "backgroundImageAttachment": { "label": "צירוף תמונת רקע", "option": { "fixed": { - "label": "", - "description": "" + "label": "קבוע", + "description": "הרקע נשאר באותו מיקום." }, "scroll": { - "label": "", - "description": "" + "label": "גלילה", + "description": "גלילה ברקע עם העכבר." } } }, "backgroundImageRepeat": { - "label": "", + "label": "חזרה על תמונת רקע", "option": { "repeat": { - "label": "", - "description": "" + "label": "חזור", + "description": "התמונה חוזרת על עצמה ככל הנדרש כדי לכסות את כל אזור ציור תמונת הרקע." }, "no-repeat": { - "label": "", - "description": "" + "label": "ללא חזרה", + "description": "התמונה אינה חוזרת על עצמה וייתכן שלא תמלא את כל החלל." }, "repeat-x": { - "label": "", - "description": "" + "label": "חזור על ציר X", + "description": "זהה ל'חזרה' אבל רק על הציר האופקי." }, "repeat-y": { - "label": "", - "description": "" + "label": "חזור על ציר Y", + "description": "זהה ל'חזרה' אבל רק על הציר האנכי." } } }, @@ -1684,12 +1916,12 @@ "label": "גודל תמונת רקע", "option": { "cover": { - "label": "", - "description": "" + "label": "כיסוי", + "description": "קנה קנה מידה קטן ככל האפשר של התמונה כדי לכסות את כל החלון על ידי חיתוך שטח מוגזם." }, "contain": { - "label": "", - "description": "" + "label": "מכיל", + "description": "קנה מידה גדול ככל האפשר של התמונה בתוך המיכל שלה מבלי לחתוך או למתוח את התמונה." } } }, @@ -1700,36 +1932,36 @@ "label": "צבע משני" }, "opacity": { - "label": "" + "label": "אטימות" }, "customCss": { - "label": "", + "label": "עיצוב מותאם אישית עבור הלוח הזה", "description": "יתר על כן, התאם את לוח המחוונים שלך באמצעות CSS, מומלץ רק למשתמשים מנוסים", "customClassesAlert": { - "title": "", - "description": "" + "title": "מחלקות מתאמות אישית", + "description": "אתה יכול להוסיף מחלקות מותאמות אישית לפריטי הלוח שלך באפשרויות המתקדמות של כל פריט ולהשתמש בהן בעיצוב המותאם אישית למעלה." } }, "columnCount": { - "label": "" + "label": "ספירת עמודות" }, "name": { "label": "שם" }, "isPublic": { "label": "ציבורי", - "description": "" + "description": "לוחות ציבוריים נגישים לכולם, גם ללא חשבון." } }, "content": { - "metaTitle": "" + "metaTitle": "לוח {boardName}" }, "setting": { - "title": "", + "title": "הגדרות עבור לוח {boardName}", "section": { "general": { "title": "כללי", - "unrecognizedLink": "" + "unrecognizedLink": "הקישור שסופק אינו מזוהה ולא יוצג בתצוגה מקדימה, ייתכן שהוא עדיין יעבוד." }, "layout": { "title": "פריסה" @@ -1738,23 +1970,23 @@ "title": "רקע" }, "color": { - "title": "" + "title": "צבעים" }, "customCss": { - "title": "" + "title": "עיצוב מותאם אישית" }, "access": { - "title": "", + "title": "בקרת גישה", "permission": { "item": { "view": { "label": "צפייה בלוח" }, "modify": { - "label": "" + "label": "שנה לוח" }, "full": { - "label": "" + "label": "גישה מלאה" } } } @@ -1763,82 +1995,115 @@ "title": "אזור מסוכן", "action": { "rename": { - "label": "", - "description": "", - "button": "", + "label": "שנה את שם הלוח", + "description": "שינוי השם ישבור כל קישור ללוח זה.", + "button": "שנה שם", "modal": { - "title": "" + "title": "שנה את שם הלוח" } }, "visibility": { - "label": "", + "label": "שנה את נראות הלוח", "description": { - "public": "", - "private": "" + "public": "הלוח הזה כרגע ציבורי.", + "private": "הלוח הזה כרגע פרטי." }, "button": { - "public": "", - "private": "" + "public": "הפוך לפרטי", + "private": "הפוך לציבורי" }, "confirm": { "public": { - "title": "", - "description": "" + "title": "הפיכת לוח לפרטי", + "description": "האם את/ה בטוח/ה להפוך את הלוח הזה לפרטי? פעולה זו תסתיר את הלוח מציבורי. קישורים למשתמשים אורחים יוסרו." }, "private": { - "title": "", - "description": "" + "title": "הפיכת לוח לציבורי", + "description": "האם את/ה בטוח/ה להפוך את הלוח הזה לציבורי? הפעולה תהפוך את הלוח נגיש לכולם." } } }, "delete": { - "label": "", - "description": "", - "button": "", + "label": "מחיקת לוח זה", + "description": "ברגע שהלוח נמחק, אין דרך חזרה. אנא וודא/י זאת בוודאות.", + "button": "מחיקת לוח זה", "confirm": { "title": "מחיקת לוח", - "description": "" + "description": "האם את/ה בטוח/ה שברצונך למחוק לוח זה? הלוח ותוכנו יימחקו לצמיתות." } } } } } + }, + "error": { + "noBoard": { + "title": "ברוכים הבאים ל- Homarr", + "description": "לוח בקרה מעוצב ומודרני שמביא את כל האפליקציות והשירותים שלך בהישג יד.", + "link": "צור את הלוח הראשון שלך", + "notice": "כדי להעלים דף זה, יש ליצור לוח ולקבוע אותו כלוח בית" + }, + "notFound": { + "title": "לא נמצא לוח", + "description": "הלוח לא נמצא או שאין לך הרשאה לגשת אליו.", + "link": "הצגת כל הלוחות", + "notice": "בדוק את הקישור או צור קשר עם מנהל אם אתה סבור שהוא אמור להיות נגיש" + }, + "homeBoard": { + "title": "אין לוח בית", + "admin": { + "description": "לא הוגדר לוח בית לשרת עדיין.", + "link": "הגדר לוח בית לשרת", + "notice": "כדי לגרום לדף זה להעלם עבור כל המשתמש, יש להגדיר לוח בית עבור השרת" + }, + "user": { + "description": "לא הגדרת עדיין לוח בית.", + "link": "הגדר/י את לוח הבית שלך", + "notice": "על מנת לגרום לדף זה להיעלם, יש לציין לוח בית בהעדפות שלך" + }, + "anonymous": { + "description": "מנהל השרת לא הגדיר עדיין לוח בית.", + "link": "הצגת לוחות ציבוריים", + "notice": "על מנת לגרום לדף זה להיעלם, בקש ממנהל השרת להגדיר לוח בית עבור השרת" + } + } } }, "management": { - "metaTitle": "", + "metaTitle": "ניהול", "title": { - "morning": "", - "afternoon": "", - "evening": "" + "morning": "בוקר טוב, {username}", + "afternoon": "צהריים טובים, {username}", + "evening": "ערב טוב, {username}" }, "notFound": { - "title": "", - "text": "" + "title": "לא נמצא", + "text": "לא ניתן לאתר את המשאב המבוקש" }, "navbar": { "items": { "home": "מסך הבית", "boards": "לוחות", "apps": "אפליקציות", - "integrations": "", - "searchEngies": "", - "medias": "", + "integrations": "אינטגרציות", + "searchEngies": "מנועי חיפוש", + "medias": "מדיה", "users": { "label": "משתמשים", "items": { "manage": "ניהול", "invites": "הזמנות", - "groups": "" + "groups": "קבוצות" } }, "tools": { "label": "כלים", "items": { "docker": "דוקר", - "logs": "", + "logs": "קובצי לוג", "api": "ממשק API", - "tasks": "" + "certificates": "", + "tasks": "משימות" } }, "settings": "הגדרות", @@ -1846,9 +2111,9 @@ "label": "עזרה", "items": { "documentation": "תיעוד", - "submitIssue": "", + "submitIssue": "שלח בעיה", "discord": "קהילת דיסקורד", - "sourceCode": "" + "sourceCode": "קוד מקור" } }, "about": "אודות" @@ -1860,47 +2125,57 @@ "board": "לוחות", "user": "משתמשים", "invite": "הזמנות", - "integration": "", + "integration": "אינטגרציות", "app": "אפליקציות", - "group": "" + "group": "קבוצות" }, "statisticLabel": { "boards": "לוחות", - "resources": "", - "authentication": "", - "authorization": "" + "resources": "מקורות", + "authentication": "אימות", + "authorization": "הרשאה" } }, "board": { "title": "הלוחות שלך", "action": { "new": { - "label": "" + "label": "לוח חדש" }, "open": { - "label": "" + "label": "פתיחת לוח" }, "settings": { "label": "הגדרות" }, "setHomeBoard": { - "label": "", + "label": "קביעה כלוח בית", "badge": { "label": "מסך הבית", + "tooltip": "הלוח הזה יוצג כלוח הבית שלך" + } + }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", "tooltip": "" } }, + "duplicate": { + "label": "שכפול לוח" + }, "delete": { "label": "מחיקה לצמיתות", "confirm": { "title": "מחיקת לוח", - "description": "" + "description": "האם את/ה בטוח/ה שברצונך למחוק את הלוח {name}?" } } }, "visibility": { - "public": "", - "private": "" + "public": "הלוח הזה ציבורי", + "private": "הלוח הזה פרטי" }, "modal": { "createBoard": { @@ -1913,17 +2188,24 @@ } }, "media": { - "includeFromAllUsers": "" + "includeFromAllUsers": "כלול מדיה מכל המשתמשים" }, "user": { - "back": "", - "fieldsDisabledExternalProvider": "", + "back": "חזרה למשתמשים", + "fieldsDisabledExternalProvider": "שדות מסוימים מושבתים מכיוון שהם מנוהלים על ידי ספק אימות חיצוני.", "setting": { "general": { "title": "כללי", "item": { - "language": "", - "board": "", + "language": "שפה ואיזור", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "מנוע חיפוש ברירת מחדל", "firstDayOfWeek": "היום הראשון בשבוע", "accessibility": "נגישות" } @@ -1940,50 +2222,50 @@ "title": "משתמשים" }, "edit": { - "metaTitle": "" + "metaTitle": "עריכת משתמש {username}" }, "create": { "metaTitle": "צור משתמש", - "title": "", + "title": "יצירת משתמש חדש", "step": { "personalInformation": { - "label": "" + "label": "פרטים אישיים" }, "security": { "label": "אבטחה" }, "groups": { - "label": "", - "title": "", - "description": "" + "label": "קבוצות", + "title": "בחירת כל הקבוצות שהמשתמש יהיה חבר בהם", + "description": "הקבוצה {everyoneGroup} מוקצת עבור כל המשתמשים ולא ניתנת להסרה." }, "review": { - "label": "" + "label": "סקירה" }, "completed": { - "title": "" + "title": "המשתמש נוצר" }, "error": { - "title": "" + "title": "יצירת המשתמש נכשלה" } }, "action": { - "createAnother": "", - "back": "" + "createAnother": "יצירת משתמש נוסף", + "back": "חזרה לרשימת משתמשים" } }, "invite": { "title": "נהל הזמנות משתמש", "action": { "new": { - "title": "", + "title": "הזמנה חדשה", "description": "לאחר התפוגה, הזמנה לא תהיה תקפה יותר ומקבל ההזמנה לא יוכל ליצור חשבון." }, "copy": { - "title": "", - "description": "", + "title": "העתקת הזמנה", + "description": "ההזמנה שלך נוצרה. לאחר שחלון זה ייסגר, לא תוכל להעתיק את הקישור הזה יותר. אם אינך מעוניין להזמין את האדם הנ\"ל, תוכל למחוק את ההזמנה בכל זמן.", "link": "קישור הזמנה", - "button": "" + "button": "העתקה וסגירה" }, "delete": { "title": "מחיקת הזמנה", @@ -2007,23 +2289,23 @@ } }, "group": { - "back": "", + "back": "חזרה לקבוצות", "setting": { "general": { "title": "כללי", - "owner": "", - "ownerOfGroup": "", - "ownerOfGroupDeleted": "" + "owner": "בעלים", + "ownerOfGroup": "בעלים של קבוצה זו", + "ownerOfGroupDeleted": "הבעלים של קבוצה זו נמחק. כרגע אין בעלים." }, "members": { - "title": "", - "search": "", - "notFound": "" + "title": "חברים", + "search": "חיפוש חבר בקבוצה", + "notFound": "לא נמצא חברים בקבוצה" }, "permissions": { - "title": "", + "title": "הרשאות", "form": { - "unsavedChanges": "" + "unsavedChanges": "ישנם שינויים שלא נשמרו!" } } } @@ -2032,127 +2314,144 @@ "title": "הגדרות", "notification": { "success": { - "message": "" + "message": "ההגדרות נשמרו בהצלחה" }, "error": { - "message": "" + "message": "נכשל בשמירת הגדרות" } }, "section": { "analytics": { - "title": "", + "title": "ניתוחים", "general": { - "title": "", - "text": "" + "title": "שליחת ניתוח נתונים אנונימי", + "text": "Homarr ישלח ניתוחים אנונימיים באמצעות התוכנה בקוד פתוח Umami. הוא לעולם אינו אוסף מידע אישי ולכן תואם לחלוטין לדרישות ה-GDPR וה-CCPA. אנו מעודדים אותך להפעיל ניתוחים, כיוון שזה מסייע לצוות הקוד הפתוח שלנו לזהות בעיות ולהעניק עדיפות למשימות שברשימת העדיפויות שלנו." }, "widgetData": { - "title": "", - "text": "" + "title": "נתוני ווידג׳ט", + "text": "שלח אילו ווידג'טים (וכמותם) הוגדרו. אינו כולל כתובות רשת, שמות או כל מידע נוסף אחר." }, "integrationData": { - "title": "", - "text": "" + "title": "נתוני אינטגרציה", + "text": "שלח אילו אינטגרציות (וכמותם) הוגדרו. לא כולל כתובות רשת, שמות או כל מידע נוסף אחר." }, "usersData": { - "title": "", - "text": "" + "title": "נתוני משתמשים", + "text": "שלח את כמות המשתמשים והאם הופעל SSO" } }, "crawlingAndIndexing": { - "title": "", - "warning": "", + "title": "סריקה והוספה לאינדקס", + "warning": "הפעלה או השבתה של הגדרות כלשהן כאן תשפיע קשות על האופן שבו מנועי החיפוש יכנסו לאינדקס ויסרקו את הדף שלך. כל הגדרה היא בקשה ותלוית הסורק להחיל את ההגדרות הללו. היישום של כל שינוי עשוי להימשך עד מספר ימים או שבועות. הגדרות מסוימות עשויות להיות ספציפיות למנועי חיפוש.", "noIndex": { - "title": "", - "text": "" + "title": "ללא אינדקס", + "text": "אל תוסיף את האתר לאינדקס במנועי חיפוש ואל תציג אותו בתוצאות חיפוש" }, "noFollow": { - "title": "", - "text": "" + "title": "ללא מעקב", + "text": "אל תעקבו אחר קישורים בזמן ההוספה לאינדקס. השבתה זו תוביל לסורקים שינסו לעקוב אחר כל הקישורים ב-Homarr." }, "noTranslate": { - "title": "", - "text": "" + "title": "ללא תרגום", + "text": "כאשר סביר להניח ששפת האתר אינה השפת שהמשתמש ירצה לקרוא, גוגל יציג קישור תרגום בתוצאות החיפוש" }, "noSiteLinksSearchBox": { - "title": "", - "text": "" + "title": "אין תיבת חיפוש של קישורי אתרים", + "text": "גוגל תבנה תיבת חיפוש עם הקישורים שנסרקו יחד עם קישורים ישירים אחרים. הפעלה זו תבקש מגוגל להשבית את התיבה הזו." } }, "board": { - "title": "", + "title": "לוחות", "homeBoard": { - "label": "", - "description": "" + "label": "לוח בית גלובלי", + "mobileLabel": "", + "description": "רק לוחות ציבוריים זמינים לבחירה" + } + }, + "search": { + "title": "חיפוש", + "defaultSearchEngine": { + "label": "מנוע חיפוש ברירת מחדל גלובלי", + "description": "אינטגרציות מנוע חיפוש לא ניתנות לסימון כאן" } }, "appearance": { - "title": "", + "title": "מראה", "defaultColorScheme": { - "label": "", + "label": "סכמת צבעים ברירת מחדל", "options": { - "light": "", - "dark": "" + "light": "בהיר", + "dark": "כהה" } } }, "culture": { - "title": "", + "title": "תרבות", "defaultLocale": { - "label": "" + "label": "שפת ברירת מחדל" } } } }, "tool": { "tasks": { - "title": "", + "title": "משימות", "status": { - "idle": "", + "idle": "ממתין", "running": "פועל", "error": "שגיאה" }, "job": { + "minecraftServerStatus": { + "label": "סטטוס שרת מיינקראפט" + }, "iconsUpdater": { - "label": "" + "label": "עדכון אייקונים" }, "analytics": { - "label": "" + "label": "ניתוחים" }, "smartHomeEntityState": { - "label": "" + "label": "סטטוס יישות בית חכם" }, "ping": { - "label": "" + "label": "פינגים" }, "mediaServer": { "label": "שרת מדיה" }, "mediaOrganizer": { - "label": "" + "label": "מארגני מדיה" }, "downloads": { - "label": "" + "label": "הורדות" }, "mediaRequestStats": { - "label": "" + "label": "סטטוס בקשות מדיה" }, "mediaRequestList": { - "label": "" + "label": "רשימת בקשות מדיה" }, "rssFeeds": { - "label": "" + "label": "הזנות RSS" }, "indexerManager": { - "label": "" + "label": "מנהל אינדקסים" }, "healthMonitoring": { - "label": "" + "label": "ניטור בריאות המערכת" }, "dnsHole": { "label": "" }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "בודק עדכונים" + }, + "mediaTranscoding": { + "label": "המרת קידוד מדיה" } } }, @@ -2162,7 +2461,7 @@ "createApiToken": { "title": "", "description": "", - "button": "" + "button": "העתקה וסגירה" } }, "tab": { @@ -2170,15 +2469,15 @@ "label": "תיעוד" }, "apiKey": { - "label": "", - "title": "", + "label": "אימות", + "title": "מפתח API", "button": { - "createApiToken": "" + "createApiToken": "יצירת מפתח  API" }, "table": { "header": { "id": "מספר מזהה", - "createdBy": "" + "createdBy": "נוצר על ידי" } } } @@ -2186,7 +2485,7 @@ } }, "about": { - "version": "", + "version": "גרסה {version}", "text": "", "accordion": { "contributors": { @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2313,7 +2631,7 @@ }, "tab": { "user": "משתמשים", - "group": "", + "group": "קבוצות", "inherited": "" }, "field": { @@ -2321,15 +2639,15 @@ "label": "משתמש" }, "group": { - "label": "" + "label": "קבוצה" }, "permission": { - "label": "" + "label": "הרשאה" } }, "action": { - "saveUser": "", - "saveGroup": "" + "saveUser": "שמירת הרשאות משתמש", + "saveGroup": "שמירת הרשאת קבוצה" } }, "navigationStructure": { @@ -2339,30 +2657,30 @@ "label": "לוחות" }, "integrations": { - "label": "", + "label": "אינטגרציות", "edit": { "label": "עריכה" }, "new": { - "label": "" + "label": "חדש" } }, "search-engines": { - "label": "", + "label": "מנועי חיפוש", "new": { - "label": "" + "label": "חדש" }, "edit": { "label": "עריכה" } }, "medias": { - "label": "" + "label": "מדיה" }, "apps": { "label": "אפליקציות", "new": { - "label": "" + "label": "חדש" }, "edit": { "label": "עריכה" @@ -2377,7 +2695,7 @@ "security": "אבטחה", "board": "לוחות", "groups": { - "label": "" + "label": "קבוצות" }, "invites": { "label": "הזמנות" @@ -2389,6 +2707,9 @@ "label": "דוקר" }, "logs": { + "label": "קבצי לוג" + }, + "certificates": { "label": "" } }, @@ -2401,28 +2722,28 @@ } }, "search": { - "placeholder": "", - "nothingFound": "", + "placeholder": "חפש משהו", + "nothingFound": "לא נמצאו תוצאות", "error": { - "fetch": "" + "fetch": "ארעה שגיאה בעת איסוף נתונים" }, "mode": { "appIntegrationBoard": { - "help": "", + "help": "חיפוש אפליקציות, אינטגרציות או לוחות", "group": { "app": { "title": "אפליקציות", "children": { "action": { "open": { - "label": "" + "label": "פתיחת קישור אפליקציה" }, "edit": { - "label": "" + "label": "ערוך אפליקציה" } }, "detail": { - "title": "" + "title": "בחירת פעולה עבור האפליקציה" } } }, @@ -2431,13 +2752,16 @@ "children": { "action": { "open": { - "label": "" + "label": "פתיחת לוח" }, "homeBoard": { + "label": "קביעה כלוח הבית" + }, + "mobileBoard": { "label": "" }, "settings": { - "label": "" + "label": "פתיחת הגדרות" } }, "detail": { @@ -2446,7 +2770,7 @@ } }, "integration": { - "title": "" + "title": "אינטגרציות" } } }, @@ -2460,8 +2784,8 @@ "title": "", "option": { "colorScheme": { - "light": "", - "dark": "" + "light": "עבור למצב בהיר", + "dark": "עבור למצב כהה" }, "language": { "label": "", @@ -2501,11 +2825,16 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { "searchEngine": { - "title": "", + "title": "מנועי חיפוש", "children": { "action": { "search": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2612,7 +2959,7 @@ "label": "" }, "manageLog": { - "label": "" + "label": "הצג לוגים" }, "manageTask": { "label": "" @@ -2624,7 +2971,7 @@ "label": "אודות" }, "homeBoard": { - "label": "" + "label": "לוח בית" }, "preferences": { "label": "העדפות שלך" @@ -2650,7 +2997,7 @@ } }, "group": { - "title": "", + "title": "קבוצות", "children": { "action": { "detail": { @@ -2684,12 +3031,12 @@ "label": "" }, "description": { - "label": "" + "label": "תיאור" } }, "page": { "list": { - "title": "", + "title": "מנועי חיפוש", "noResults": { "title": "", "action": "" @@ -2713,11 +3060,11 @@ "title": "", "notification": { "success": { - "title": "", + "title": "השינויים הוחלו בהצלחה", "message": "" }, "error": { - "title": "", + "title": "לא ניתן להחיל שינויים", "message": "" } }, @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/hr.json b/packages/translation/src/lang/hr.json index 0fcc1d3ca..a4c17566d 100644 --- a/packages/translation/src/lang/hr.json +++ b/packages/translation/src/lang/hr.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "aplikacije", + "boards": "Daske", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "Znak", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "Postavke", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "Korisnici", "name": "Korisnik", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "aplikacije", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "aplikacije", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "Prethodno", "next": "Sljedeći", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Pokušaj ponovno", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Prijaviti se", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Opasna zona", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -908,13 +1043,13 @@ "label": "" }, "layout": { - "label": "", + "label": "Raspored", "option": { "row": { - "label": "" + "label": "Horizontalno" }, "column": { - "label": "" + "label": "Okomito" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "", "dnsQueriesToday": "Upiti danas", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Bilježnica", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Vaš preglednik ne podržava iframeove. Ažurirajte svoj preglednik." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "", + "queue": "Red čekanja", + "statistics": "" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "", + "status": { + "healthy": "", + "unhealthy": "" + } + }, + "panel": { + "statistics": { + "empty": "Isprazni", + "transcodes": "", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "" + }, + "workers": { + "empty": "Isprazni", + "table": { + "file": "", + "eta": "", + "progress": "Napredak", + "transcode": "", + "healthCheck": "" + } + }, + "queue": { + "empty": "Isprazni", + "table": { + "file": "", + "size": "Veličina", + "transcode": "", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Mali", "md": "Srednji", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Izbriši trajno", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Općenito", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Prvi dan u tjednu", "accessibility": "Pristupačnost" } @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Daske", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Izgled", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Pogreška" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/hu.json b/packages/translation/src/lang/hu.json index 5d0362003..7908d29c4 100644 --- a/packages/translation/src/lang/hu.json +++ b/packages/translation/src/lang/hu.json @@ -1,26 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "Üdvözöljük a Homarrban", + "subtitle": "Kezdjük el a Homarr-példány beállítását.", + "description": "A kezdéshez válassza ki, hogyan szeretné beállítani a Homarr-példányt.", + "action": { + "scratch": "Kezdjük a legelejétől", + "importOldmarr": "Importálás Homarr 1.0 előtti verzióból" + } + }, + "import": { + "title": "Importálás", + "subtitle": "Importálhat adatokat egy meglévő Homarr-példányból.", + "dropzone": { + "title": "Húzza ide a zip fájlt, vagy kattintson a böngészéshez", + "description": "A feltöltött zip fájlt feldolgozzuk, és kiválaszthatja, hogy mit szeretne importálni" + }, + "fileInfo": { + "action": { + "change": "Fájl módosítása" + } + }, + "importSettings": { + "title": "Beállítások importálása", + "description": "Az importálási viselkedés konfigurálása" + }, + "boardSelection": { + "title": "Talált {count} táblák", + "description": "Válassza ki az összes olyan méretű táblát, amelyet importálni szeretne", + "action": { + "selectAll": "Összes kijelölése", + "unselectAll": "Kijelölés megszüntetése" + } + }, + "summary": { + "title": "Import összefoglaló", + "description": "Az alábbi összefoglalóban láthatja, hogy mi lesz importálva", + "action": { + "import": "Importálás megerősítése és folytatás" + }, + "entities": { + "apps": "Alkalmazások", + "boards": "Táblák", + "integrations": "Integrációk", + "credentialUsers": "Hitelesített felhasználók" + } + }, + "tokenModal": { + "title": "Import token megadása", + "field": { + "token": { + "label": "", + "description": "Írja be a megjelenített import tokent az előző homarr példányból" + } + }, + "notification": { + "error": { + "title": "Érvénytelen token", + "message": "A megadott token érvénytelen" + } + } + } + }, + "user": { + "title": "Admin felhasználó", + "subtitle": "Adja meg a rendszergazda felhasználó hitelesítő adatait.", + "notification": { + "success": { + "title": "Létrejött a felhasználó", + "message": "A felhasználót sikeresen létrehoztuk" + }, + "error": { + "title": "A felhasználó létrehozása sikertelen" + } + } + }, + "group": { + "title": "Külső csoport", + "subtitle": "Adja meg a külső felhasználók számára használandó csoportot.", + "form": { + "name": { + "label": "Csoportnév", + "description": "A névnek meg kell egyeznie a külső szolgáltató admin csoportjával" + } + } + }, + "settings": { + "title": "Beállítások", + "subtitle": "Szerver beállítások konfigurálása." + }, + "finish": { + "title": "Beállítás befejezése", + "subtitle": "Készen állsz!", + "description": "Sikeresen befejezte a beállítási folyamatot. Most már használhatja a Homarr-t. Válassza ki a következő műveletet:", + "action": { + "goToBoard": "Tovább a {name} oldalra", + "createBoard": "Az első tábla létrehozása", + "inviteUser": "Más felhasználók meghívása", + "docs": "Olvassa el a dokumentációt" + } + } + }, + "backToStart": "Vissza a starthoz" + }, "user": { "title": "Felhasználók", "name": "Felhasználó", "page": { "login": { - "title": "", - "subtitle": "" + "title": "Jelentkezzen be a fiókjába", + "subtitle": "Üdvözöljük újra! Kérjük, adja meg hitelesítő adatait" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "Csatlakozz Homarrhoz", + "subtitle": "Üdvözöljük a Homarrban! Kérjük, hozza létre fiókját", + "description": "{username} meghívott" }, "init": { - "title": "", - "subtitle": "" + "title": "Új Homarr telepítés", + "subtitle": "Kérjük, hozza létre a kezdeti rendszergazda felhasználót" } }, "field": { "email": { "label": "Email cím", - "verified": "" + "verified": "Ellenőrzött" }, "username": { "label": "Felhasználónév" @@ -28,46 +133,46 @@ "password": { "label": "Jelszó", "requirement": { - "length": "", + "length": "Tartalmazzon legalább 8 karaktert", "lowercase": "Tartalmazzon kisbetűt", "uppercase": "Tartalmazzon nagybetűt", "number": "Tartalmazzon számot", - "special": "" + "special": "Különleges szimbólumot tartalmaz" } }, "passwordConfirm": { "label": "Jelszó megerősítése" }, "previousPassword": { - "label": "" + "label": "Előző jelszó" }, "homeBoard": { - "label": "" + "label": "Főoldal" }, "pingIconsEnabled": { - "label": "" + "label": "Ikonok használata a pingekhez" } }, "error": { - "usernameTaken": "" + "usernameTaken": "A felhasználónév már foglalt" }, "action": { "login": { "label": "Bejelentkezés", - "labelWith": "", + "labelWith": "Bejelentkezés {provider} fiókkal", "notification": { "success": { - "title": "", - "message": "" + "title": "Belépés sikeres", + "message": "Be van jelentkezve" }, "error": { - "title": "", - "message": "" + "title": "Belépés sikertelen", + "message": "Belépés sikertelen" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "Elfelejtette a jelszavát?", + "description": "A rendszergazda a következő paranccsal állíthatja vissza a jelszavát:" } }, "register": { @@ -75,27 +180,37 @@ "notification": { "success": { "title": "Fiók létrehozva", - "message": "" + "message": "Kérjük, jelentkezzen be a folytatáshoz" }, "error": { - "title": "", - "message": "" + "title": "Fiók létrehozása sikertelen", + "message": "Fiókját nem sikerült létrehozni" } } }, "create": "Felhasználó létrehozása", "changePassword": { - "label": "", + "label": "Jelszó módosítása", "notification": { "success": { - "message": "" + "message": "Jelszó sikeresen megváltozott" }, "error": { - "message": "" + "message": "Nem lehet megváltoztatni a jelszót" } } }, "changeHomeBoard": { + "notification": { + "success": { + "message": "A kezdőlap sikeresen cserélve" + }, + "error": { + "message": "A kezdőlap cseréje nem lehetséges" + } + } + }, + "changeDefaultSearchEngine": { "notification": { "success": { "message": "" @@ -108,48 +223,48 @@ "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "A hét első napja sikeresen megváltozott" }, "error": { - "message": "" + "message": "A hét első napja nem módosítható" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "A ping ikonok sikeresen váltakoztak" }, "error": { - "message": "" + "message": "Nem lehet ping ikonokat megváltoztatni" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Képcsere", "notification": { "success": { - "message": "" + "message": "A kép sikeresen megváltozott" }, "error": { - "message": "" + "message": "A kép nem módosítható" }, "toLarge": { - "title": "", - "message": "" + "title": "A kép túl nagy", + "message": "A maximális képméret {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Kép eltávolítása", + "confirm": "Valóban törölni szeretnéd ezt a képet?", "notification": { "success": { - "message": "" + "message": "Kép sikeresen eltávolítva" }, "error": { - "message": "" + "message": "Nem sikerült eltávolítani a képet" } } } @@ -157,63 +272,63 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "A profil sikeresen frissítve" }, "error": { - "message": "" + "message": "Nem sikerült frissíteni a profilt" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "Felhasználó végleges törlése", + "description": "Törli ezt a felhasználót, beleértve a beállításait. Nem töröl egyetlen táblát sem. A felhasználó nem kap értesítést.", + "confirm": "Biztos benne, hogy törli a {username} felhasználót a beállításaival együtt?" }, "select": { - "label": "", - "notFound": "" + "label": "Felhasználó kiválasztása", + "notFound": "Felhasználó nem található" }, "transfer": { - "label": "" + "label": "Válasszon új tulajdonost" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "Csoportok", + "name": "Csoport", + "search": "Csoport keresése", "field": { "name": "Név", - "members": "" + "members": "Tagok" }, "permission": { "admin": { "title": "Adminisztrátor", "item": { "admin": { - "label": "", - "description": "" + "label": "Admin", + "description": "Az ezzel az engedéllyel rendelkező tagok teljes hozzáféréssel rendelkeznek az összes funkcióhoz és beállításhoz" } } }, "app": { - "title": "", + "title": "Alkalmazások", "item": { "create": { - "label": "", - "description": "" + "label": "Alkalmazások létrehozása", + "description": "Alkalmazások létrehozásának engedélyezése a tagoknak" }, "use-all": { - "label": "", - "description": "" + "label": "Minden alkalmazás használata", + "description": "Lehetővé teszi a tagok számára, hogy bármilyen alkalmazást hozzáadjanak a tábláikhoz" }, "modify-all": { - "label": "", - "description": "" + "label": "Minden alkalmazás módosítása", + "description": "A tagok módosíthatják az összes alkalmazást" }, "full-all": { - "label": "", - "description": "" + "label": "Teljes alkalmazás hozzáférés", + "description": "Lehetővé teszi a tagoknak, hogy kezeljék, használják és töröljék az alkalmazásokat" } } }, @@ -221,214 +336,215 @@ "title": "Táblák", "item": { "create": { - "label": "", - "description": "" + "label": "Tábla létrehozása", + "description": "A tagok táblákat hozhatnak létre" }, "view-all": { - "label": "", - "description": "" + "label": "Az összes tábla megtekintése", + "description": "A tagok megtekinthetik az összes táblát" }, "modify-all": { - "label": "", - "description": "" + "label": "Az összes tábla módosítása", + "description": "Lehetővé teszi a tagoknak, hogy módosítsák az összes táblát (Nem tartalmazza a beléptetést és a veszélyes zónát)" }, "full-all": { - "label": "", - "description": "" + "label": "Teljes alkalmazás hozzáférés", + "description": "Lehetővé teszi a tagoknak az összes tábla megtekintését, módosítását és törlését (beleértve a beléptetést és a veszélyzónát)" } } }, "integration": { - "title": "", + "title": "Integrációk", "item": { "create": { - "label": "", - "description": "" + "label": "Integrációk létrehozása", + "description": "A tagok integrációkat hozhatnak létre" }, "use-all": { - "label": "", - "description": "" + "label": "Használja az összes integrációt", + "description": "Lehetővé teszi a tagok számára, hogy bármilyen integrációt hozzáadjanak a tábláikhoz" }, "interact-all": { - "label": "", - "description": "" + "label": "Interakció bármely integrációval", + "description": "Lehetővé teszi a tagoknak, hogy bármilyen integrációval kapcsolatba lépjenek" }, "full-all": { - "label": "", - "description": "" + "label": "Teljes integrációs hozzáférés", + "description": "Lehetővé teszi a tagoknak, hogy kezeljék, használhassák és kapcsolatba lépjenek bármilyen integrációval" } } }, "media": { - "title": "", + "title": "Média", "item": { "upload": { - "label": "", - "description": "" + "label": "Média feltöltése", + "description": "Engedélyezze a tagok számára a médiák feltöltését" }, "view-all": { - "label": "", - "description": "" + "label": "Az összes média megtekintése", + "description": "Engedélyezze a tagok számára az összes média megtekintését" }, "full-all": { - "label": "", - "description": "" + "label": "Teljes médiahozzáférés", + "description": "Lehetővé teszi a tagoknak, hogy kezeljék és töröljék a médiatartalmakat" } } }, "other": { - "title": "", + "title": "Egyéb", "item": { "view-logs": { - "label": "", - "description": "" + "label": "Naplók megtekintése", + "description": "A tagok megtekinthetik a naplókat" } } }, "search-engine": { - "title": "", + "title": "Keresőmotorok", "item": { "create": { - "label": "", - "description": "" + "label": "Egyéni keresőmotor", + "description": "A tagok egyéni keresőmotorokat hozhatnak létre" }, "modify-all": { - "label": "", - "description": "" + "label": "Módosítsa az összes keresőmotort", + "description": "A tagok módosíthatják az összes a keresőmotorokat" }, "full-all": { - "label": "", - "description": "" + "label": "Teljes hozzáférés a keresőmotorokhoz", + "description": "Lehetővé teszi a tagoknak, hogy kezeljék és töröljék a keresőmotorokat" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "Egyes tagok külső szolgáltatóktól származnak, és itt nem kezelhetők", + "external": "Minden tag külső szolgáltatótól származik, és itt nem kezelhetők" }, "reservedNotice": { - "message": "" + "message": "Ez a csoport a rendszer használatára van fenntartva, és korlátoz bizonyos műveleteket. " }, "action": { "create": { - "label": "", + "label": "Új csoport", "notification": { "success": { - "message": "" + "message": "A csoport sikeresen létrejött" }, "error": { - "message": "" + "message": "A csoport létrehozása nem sikerült" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "Tulajdonos megváltoztatása", + "description": "A csoport tulajdonjogának átadása másik felhasználónak.", + "confirm": "Biztosan át akarja adni a {name} csoport tulajdonjogát {username}felhasználónak?", "notification": { "success": { - "message": "" + "message": "A {group} csoport sikeresen áthelyezve {user} felhasználó tulajdonába" }, "error": { - "message": "" + "message": "Nem lehet átruházni a tulajdonjogot" } } }, "addMember": { - "label": "" + "label": "Tag hozzáadása" }, "removeMember": { - "label": "", - "confirm": "" + "label": "Tag eltávolítása", + "confirm": "Biztos, hogy el akarod távolítani a {user} felhasználót ebből a csoportból?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "Csoport törlése", + "description": "Ha töröl egy csoportot, az végleges. Kérjük, legyen biztos benne.", + "confirm": "Biztosan törli a {name} csoportot?", "notification": { "success": { - "message": "" + "message": "A {name} csoport sikeresen törölve" }, "error": { - "message": "" + "message": "A {name} csoport nem törölhető" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "Engedélyek mentve", + "message": "Engedélyek mentése sikeresen megtörtént" }, "error": { - "title": "", - "message": "" + "title": "Engedélyek nincsenek mentve", + "message": "Engedélyek nem kerültek mentésre" } } }, "update": { "notification": { "success": { - "message": "" + "message": "A {name} csoport mentése sikeresen megtörtént" }, "error": { - "message": "" + "message": "Nem sikerült menteni a {name} csoportot" } } }, "select": { - "label": "", - "notFound": "" + "label": "Csoport kiválasztása", + "notFound": "Nem található csoport" } } }, "app": { + "search": "", "page": { "list": { "title": "Alkalmazások", "noResults": { - "title": "", - "action": "" + "title": "Még nincsenek alkalmazások", + "action": "Hozza létre első alkalmazását" } }, "create": { - "title": "", + "title": "Új alkalmazás", "notification": { "success": { - "title": "", - "message": "" + "title": "Sikeres létrehozás", + "message": "Az alkalmazás sikeresen létrejött" }, "error": { - "title": "", - "message": "" + "title": "A létrehozás nem sikerült", + "message": "Az alkalmazást nem sikerült létrehozni" } } }, "edit": { - "title": "", + "title": "Alkalmazás szerkesztése", "notification": { "success": { - "title": "", - "message": "" + "title": "A módosítások sikeresen alkalmazva", + "message": "Az alkalmazás sikeresen mentve" }, "error": { - "title": "", - "message": "" + "title": "Nem sikerült alkalmazni a változtatásokat", + "message": "Az alkalmazást nem sikerült menteni" } } }, "delete": { - "title": "", - "message": "", + "title": "Törölje az alkalmazást", + "message": "Biztosan törli a {name} alkalmazást?", "notification": { "success": { - "title": "", - "message": "" + "title": "Sikeres törlés", + "message": "Az alkalmazás sikeresen törölve" }, "error": { - "title": "", - "message": "" + "title": "Törlés sikertelen", + "message": "Nem lehet törölni az alkalmazást" } } } @@ -438,7 +554,7 @@ "label": "Név" }, "description": { - "label": "" + "label": "Leírás" }, "url": { "label": "" @@ -446,57 +562,57 @@ }, "action": { "select": { - "label": "", - "notFound": "" + "label": "Alkalmazás kiválasztása", + "notFound": "Nem található alkalmazás" } } }, "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "Integrációk", + "search": "Integrációk közötti keresés", "noResults": { - "title": "" + "title": "Még nincsenek integrációk" } }, "create": { - "title": "", + "title": "Új {name} integráció", "notification": { "success": { - "title": "", - "message": "" + "title": "Sikeres létrehozás", + "message": "Az integráció sikeresen létrejött" }, "error": { - "title": "", - "message": "" + "title": "A létrehozás nem sikerült", + "message": "Az integráció nem hozható létre" } } }, "edit": { - "title": "", + "title": "A {name} integráció szerkesztése", "notification": { "success": { - "title": "", - "message": "" + "title": "A módosítások sikeresen alkalmazva", + "message": "Az integráció sikeresen mentve" }, "error": { - "title": "", - "message": "" + "title": "Nem sikerült alkalmazni a változtatásokat", + "message": "Az integrációt nem sikerült menteni" } } }, "delete": { - "title": "", - "message": "", + "title": "Integráció törlése", + "message": "Biztosan törli a {name} integrációt?", "notification": { "success": { - "title": "", - "message": "" + "title": "Sikeres törlés", + "message": "Az integráció sikeresen törölve" }, "error": { - "title": "", - "message": "" + "title": "Törlés sikertelen", + "message": "Az integráció nem törölhető" } } } @@ -507,104 +623,112 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { - "create": "" + "create": "Új integráció" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "Tesztelje a kapcsolatot és hozzon létre", + "edit": "Tesztelje a kapcsolatot és mentsen" }, - "alertNotice": "", + "alertNotice": "A Mentés gomb a sikeres kapcsolat létrehozása után aktiválódik", "notification": { "success": { - "title": "", - "message": "" + "title": "Sikeres csatlakozás", + "message": "A kapcsolat sikeresen létrejött" }, "invalidUrl": { "title": "Érvénytelen URL", - "message": "" + "message": "Az URL érvénytelen" }, "secretNotDefined": { - "title": "", - "message": "" + "title": "Hiányzó hitelesítő adatok", + "message": "Nem adtak meg minden hitelesítő adatot" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "Érvénytelen hitelesítő adatok", + "message": "A hitelesítő adatok érvénytelenek" }, "commonError": { - "title": "", - "message": "" + "title": "Sikertelen kapcsolódás", + "message": "A kapcsolat nem hozható létre" }, "badRequest": { - "title": "", - "message": "" + "title": "Hibás kérés", + "message": "A kérés hibás volt" }, "unauthorized": { - "title": "", - "message": "" + "title": "Jogosulatlan", + "message": "Valószínűleg rossz hitelesítő adatok" }, "forbidden": { - "title": "", - "message": "" + "title": "Elutasítva", + "message": "Valószínűleg hiányoznak az engedélyek" }, "notFound": { - "title": "", - "message": "" + "title": "Nem található", + "message": "Valószínűleg rossz url vagy elérési útvonal" }, "internalServerError": { - "title": "", - "message": "" + "title": "Belső szerverhiba", + "message": "A szerver hibát észlelt" }, "serviceUnavailable": { - "title": "", - "message": "" + "title": "A szolgáltatás nem elérhető", + "message": "A szerver jelenleg nem elérhető" }, "connectionAborted": { - "title": "", - "message": "" + "title": "A kapcsolat megszakadt", + "message": "A kapcsolat megszakadt" }, "domainNotFound": { - "title": "", - "message": "" + "title": "A domain nem található", + "message": "A domain nem található" }, "connectionRefused": { - "title": "", - "message": "" + "title": "Csatlakozás elutasítva", + "message": "Csatlakozás elutasítva" }, "invalidJson": { - "title": "", - "message": "" + "title": "Hibás JSON", + "message": "A válasz nem érvényes JSON" }, "wrongPath": { - "title": "", - "message": "" + "title": "Rossz útvonal", + "message": "Az útvonal valószínűleg nem helyes" } } }, "secrets": { - "title": "", - "lastUpdated": "", - "secureNotice": "", + "title": "Titkok", + "lastUpdated": "Utoljára frissítve: {date}", + "notSet": { + "label": "Nincs beállítva érték", + "tooltip": "Ez a szükséges titok még nincs beállítva" + }, + "secureNotice": "Ezt a titkot a létrehozás után nem lehet visszakeresni", "reset": { - "title": "", - "message": "" + "title": "Titok visszaállítása", + "message": "Biztosan valaphelyzetbe állítja ezt a titkot?" }, "noSecretsRequired": { - "segmentTitle": "", - "text": "" + "segmentTitle": "Nincsenek titkok", + "text": "Ehhez az integrációhoz nincs szükség titkokra" }, "kind": { "username": { "label": "Felhasználónév", - "newLabel": "" + "newLabel": "Új felhasználónév" }, "apiKey": { - "label": "", - "newLabel": "" + "label": "API Kulcs", + "newLabel": "Új API kulcs" }, "password": { "label": "Jelszó", @@ -613,14 +737,14 @@ } }, "permission": { - "use": "", - "interact": "", - "full": "" + "use": "Válassza ki az integrációkat az elemekben", + "interact": "Interakció az integrációkkal", + "full": "Teljes integrációs hozzáférés" } }, "media": { - "plural": "", - "search": "", + "plural": "Média", + "search": "Média keresése", "field": { "name": "Név", "size": "Méret", @@ -628,83 +752,90 @@ }, "action": { "upload": { - "label": "", - "file": "", + "label": "Média feltöltése", + "file": "Fájl kiválasztása", "notification": { "success": { - "message": "" + "message": "A média sikeresen feltöltve" }, "error": { - "message": "" + "message": "A médiát nem lehetett feltölteni" } } }, "delete": { - "label": "", - "description": "", + "label": "Média törlése", + "description": "Biztos, hogy törölni akarja a médiát ?", "notification": { "success": { - "message": "" + "message": "A média sikeresen törölve" }, "error": { - "message": "" + "message": "A médiát nem lehetett törölni" } } }, "copy": { - "label": "" + "label": "URL másolása" } } }, "common": { - "beta": "", + "beta": "Béta", "error": "Hiba", "action": { "add": "Hozzáadás", "apply": "Alkalmaz", - "backToOverview": "", + "backToOverview": "Vissza az áttekintéshez", "create": "Létrehozás", "edit": "Szerkesztés", - "import": "", + "import": "Importálás", "insert": "Beillesztés", "remove": "Eltávolítás", "save": "Mentés", "saveChanges": "Változások mentése", "cancel": "Mégse", "delete": "Törlés", - "discard": "", + "discard": "Elvetés", "confirm": "Megerősít", - "continue": "", + "continue": "Folytatás", "previous": "Előző", "next": "Következő", - "checkoutDocs": "", + "checkoutDocs": "Tekintse meg a dokumentációt", + "checkLogs": "További részletekért ellenőrizze a naplókat", "tryAgain": "Próbálja újra", - "loading": "" + "loading": "Töltés" }, - "here": "", + "here": "itt", "iconPicker": { - "label": "", - "header": "" + "label": "Ikonhivatkozás", + "header": "Írjon be nevet vagy objektumokat az ikonok szűréséhez... A Homarr a {countIcons} ikonok között keres." + }, + "colorScheme": { + "options": { + "light": "Világos", + "dark": "Sötét" + } }, "information": { - "min": "", - "max": "", + "min": "Legalább", + "max": "Legfeljebb", "days": "", "hours": "Óra", "minutes": "Perc" }, "notification": { "create": { - "success": "", - "error": "" + "success": "Sikeres létrehozás", + "error": "A létrehozás nem sikerült" }, "delete": { - "success": "", - "error": "" + "success": "Sikeres törlés", + "error": "Törlés sikertelen" }, "update": { - "success": "", - "error": "" + "success": "A módosítások sikeresen alkalmazva", + "error": "Nem sikerült alkalmazni a változtatásokat" }, "transfer": { "success": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Bejelentkezés", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Veszélyzóna", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -832,8 +966,9 @@ } }, "create": { - "title": "", - "addToBoard": "" + "title": "Válassza ki a hozzáadni kívánt elemet", + "search": "", + "addToBoard": "Hozzáadás a táblához" }, "moveResize": { "title": "", @@ -845,91 +980,91 @@ "label": "Magasság" }, "xOffset": { - "label": "" + "label": "X eltolás" }, "yOffset": { - "label": "" + "label": "Y eltolás" } } }, "edit": { "title": "", "advancedOptions": { - "label": "", - "title": "" + "label": "Haladó beállítások", + "title": "Speciális tételbeállítások" }, "field": { "integrations": { - "label": "" + "label": "Integrációk" }, "customCssClasses": { - "label": "" + "label": "Egyedi css osztályok" } } }, "remove": { "title": "", - "message": "" + "message": "Biztosan eltávolítja ezt az elemet?" } }, "widget": { "app": { - "name": "", - "description": "", + "name": "Alkalmazás", + "description": "Alkalmazást ágyaz be a táblába.", "option": { "appId": { - "label": "" + "label": "Válasszon alkalmazást" }, "openInNewTab": { "label": "Megnyitás új lapon" }, "showTitle": { - "label": "" + "label": "Alkalmazás nevének megjelenítése" }, "showDescriptionTooltip": { - "label": "" + "label": "Leírás elemleírás megjelenítése" }, "pingEnabled": { - "label": "" + "label": "Egyszerű ping engedélyezése" } }, "error": { "notFound": { - "label": "", - "tooltip": "" + "label": "Nincs alkalmazás", + "tooltip": "Nem választott ki érvényes alkalmazást" } } }, "bookmarks": { - "name": "", - "description": "", + "name": "Könyjelzők", + "description": "Több alkalmazáshivatkozást jelenít meg", "option": { "title": { - "label": "" + "label": "Cím" }, "layout": { - "label": "", + "label": "Elrendezés", "option": { "row": { - "label": "" + "label": "Vízszintes" }, "column": { - "label": "" + "label": "Függőleges" }, "grid": { - "label": "" + "label": "Rács" } } }, "items": { - "label": "", - "add": "" + "label": "Könyjelzők", + "add": "Könyvjelző hozzáadása" } } }, "dnsHoleSummary": { - "name": "", - "description": "", + "name": "DNS Blokkoló Összefoglaló", + "description": "Megjeleníti a DNS Blokkoló összefoglalóját", "option": { "layout": { "label": "Elrendezés", @@ -941,27 +1076,28 @@ "label": "Függőleges" }, "grid": { - "label": "" + "label": "Rács" } } }, "usePiHoleColors": { - "label": "" + "label": "Használjon Pi-Hole színeket" } }, "error": { - "internalServerError": "", - "integrationsDisconnected": "" + "internalServerError": "Nem sikerült lekérni a DNS Hole összefoglalóját", + "integrationsDisconnected": "Nem állnak rendelkezésre adatok, minden integráció megszakadt" }, "data": { "adsBlockedToday": "Mai blokkolások", "adsBlockedTodayPercentage": "Mai blokkolások", "dnsQueriesToday": "Mai lekérdezések", - "domainsBeingBlocked": "" - } + "domainsBeingBlocked": "Domainek a tiltólistán" + }, + "domainsTooltip": "" }, "dnsHoleControls": { - "name": "", + "name": "DNS blokkolók ellenőrzése", "description": "A PiHole vagy az AdGuard vezérlése a műszerfalról", "option": { "layout": { @@ -974,68 +1110,87 @@ "label": "Függőleges" }, "grid": { - "label": "" + "label": "Rács" } } }, "showToggleAllButtons": { - "label": "" + "label": "Összes gomb megjelenítése" } }, "error": { - "internalServerError": "" + "internalServerError": "Nem sikerült vezérelni a DNS Blokkolót" }, "controls": { - "enableAll": "", - "disableAll": "", - "setTimer": "", + "enableAll": "Az összes engedélyezése", + "disableAll": "Az összes tiltása", + "setTimer": "Időzítő beállítása", "set": "Beállít", "enabled": "Engedélyezve", "disabled": "Letiltva", - "processing": "", - "disconnected": "", + "processing": "Feldolgozás", + "disconnected": "Szétkapcsolt", "hours": "Óra", "minutes": "Perc", - "unlimited": "" + "unlimited": "Hagyja üresen a korlátlanhoz" } }, "clock": { - "name": "", + "name": "Dátum és idő", "description": "Megjeleníti az aktuális dátumot és időt.", "option": { "customTitleToggle": { - "label": "", - "description": "" + "label": "Egyedi cím/város megjelenítése", + "description": "Mutasson egy egyéni címet vagy a város/ország nevét az óra tetején." }, "customTitle": { - "label": "" + "label": "Cím" }, "is24HourFormat": { - "label": "", - "description": "" + "label": "24 órás formátum", + "description": "12 órás formátum helyett 24 órás formátumot használjon" }, "showSeconds": { - "label": "" + "label": "Másodpercek kijelzése" }, "useCustomTimezone": { - "label": "" + "label": "Használjon rögzített időzónát" }, "timezone": { "label": "Időzóna", - "description": "" + "description": "Válassza ki az IANA szabványnak megfelelő időzónát" }, "showDate": { - "label": "" + "label": "Mutasd a dátumot" }, "dateFormat": { - "label": "", - "description": "" + "label": "Dátum formátum", + "description": "Hogyan nézzen ki a dátum" } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Jegyzettömb", - "description": "", + "description": "Egy egyszerű notebook widget, amely támogatja a leértékelést", "option": { "showToolbar": { "label": "A markdown írást segítő eszköztár megjelenítése" @@ -1127,12 +1282,13 @@ } }, "error": { - "noUrl": "", + "noUrl": "Nincs megadva iFrame URL", + "unsupportedProtocol": "", "noBrowerSupport": "Az Ön böngészője nem támogatja a beágyazott kereteket. Kérjük, frissítse böngészőjét." } }, "smartHome-entityState": { - "name": "", + "name": "Egység állapota", "description": "", "option": { "entityId": { @@ -1205,8 +1361,8 @@ "description": "" }, "dateFormat": { - "label": "", - "description": "" + "label": "Dátum formátum", + "description": "Hogyan nézzen ki a dátum" } }, "kind": { @@ -1304,13 +1460,10 @@ "description": "" }, "app": { - "noData": "", + "noData": "Nem található alkalmazás", "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1455,7 +1613,7 @@ "paused": "Szünet", "completed": "Kész", "failed": "", - "processing": "", + "processing": "Feldolgozás", "leeching": "", "stalled": "", "unknown": "Ismeretlen", @@ -1500,7 +1658,7 @@ "availability": { "unknown": "Ismeretlen", "pending": "", - "processing": "", + "processing": "Feldolgozás", "partiallyAvailable": "Részleges", "available": "Elérhető" }, @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "Alapértelmezett nézet" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "Munkások", + "queue": "Várólista", + "statistics": "Statisztikák" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "Sorban áll", + "status": { + "healthy": "Egészséges", + "unhealthy": "Egészségtelen" + } + }, + "panel": { + "statistics": { + "empty": "Üres", + "transcodes": "Átkódolás", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "Kodekek", + "videoContainers": "Tartály", + "videoResolutions": "Felbontás" + }, + "workers": { + "empty": "Üres", + "table": { + "file": "Fájl", + "eta": "Hátralévő idő", + "progress": "Folyamat", + "transcode": "Átkódolás", + "healthCheck": "" + } + }, + "queue": { + "empty": "Üres", + "table": { + "file": "Fájl", + "size": "Méret", + "transcode": "Átkódolás", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,7 +1775,9 @@ }, "board": { "action": { - "edit": { + "duplicate": { + "title": "", + "message": "", "notification": { "success": { "title": "", @@ -1568,6 +1787,18 @@ "title": "", "message": "" } + } + }, + "edit": { + "notification": { + "success": { + "title": "A módosítások sikeresen alkalmazva", + "message": "" + }, + "error": { + "title": "Nem sikerült alkalmazni a változtatásokat", + "message": "" + } }, "confirmLeave": { "title": "", @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Kicsi", "md": "Közepes", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "Üdvözöljük a Homarrban", + "description": "", + "link": "Az első tábla létrehozása", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "Az összes tábla megtekintése", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1821,15 +2085,15 @@ "home": "Nyitólap", "boards": "Táblák", "apps": "Alkalmazások", - "integrations": "", - "searchEngies": "", - "medias": "", + "integrations": "Integrációk", + "searchEngies": "Keresőmotorok", + "medias": "Média", "users": { "label": "Felhasználók", "items": { "manage": "Kezelés", "invites": "Meghívók", - "groups": "" + "groups": "Csoportok" } }, "tools": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1860,9 +2125,9 @@ "board": "Táblák", "user": "Felhasználók", "invite": "Meghívók", - "integration": "", + "integration": "Integrációk", "app": "Alkalmazások", - "group": "" + "group": "Csoportok" }, "statisticLabel": { "boards": "Táblák", @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Végleges törlés", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Általános", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "A hét első napja", "accessibility": "Kisegítő lehetőségek" } @@ -1953,7 +2235,7 @@ "label": "Biztonság" }, "groups": { - "label": "", + "label": "Csoportok", "title": "", "description": "" }, @@ -1961,10 +2243,10 @@ "label": "" }, "completed": { - "title": "" + "title": "Létrejött a felhasználó" }, "error": { - "title": "" + "title": "A felhasználó létrehozása sikertelen" } }, "action": { @@ -2011,12 +2293,12 @@ "setting": { "general": { "title": "Általános", - "owner": "", + "owner": "Tulajdonos", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, "members": { - "title": "", + "title": "Tagok", "search": "", "notFound": "" }, @@ -2079,19 +2361,27 @@ } }, "board": { - "title": "", + "title": "Táblák", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Megjelenés", "defaultColorScheme": { "label": "", "options": { - "light": "", - "dark": "" + "light": "Világos", + "dark": "Sötét" } } }, @@ -2112,6 +2402,9 @@ "error": "Hiba" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2131,7 +2424,7 @@ "label": "" }, "downloads": { - "label": "" + "label": "Letöltések" }, "mediaRequestStats": { "label": "" @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2313,7 +2631,7 @@ }, "tab": { "user": "Felhasználók", - "group": "", + "group": "Csoportok", "inherited": "" }, "field": { @@ -2321,7 +2639,7 @@ "label": "Felhasználó" }, "group": { - "label": "" + "label": "Csoport" }, "permission": { "label": "" @@ -2339,7 +2657,7 @@ "label": "Táblák" }, "integrations": { - "label": "", + "label": "Integrációk", "edit": { "label": "Szerkesztés" }, @@ -2348,7 +2666,7 @@ } }, "search-engines": { - "label": "", + "label": "Keresőmotorok", "new": { "label": "" }, @@ -2357,7 +2675,7 @@ } }, "medias": { - "label": "" + "label": "Média" }, "apps": { "label": "Alkalmazások", @@ -2377,7 +2695,7 @@ "security": "Biztonság", "board": "Táblák", "groups": { - "label": "" + "label": "Csoportok" }, "invites": { "label": "Meghívók" @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2418,7 +2739,7 @@ "label": "" }, "edit": { - "label": "" + "label": "Alkalmazás szerkesztése" } }, "detail": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2446,7 +2770,7 @@ } }, "integration": { - "title": "" + "title": "Integrációk" } } }, @@ -2501,11 +2825,16 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { "searchEngine": { - "title": "", + "title": "Keresőmotorok", "children": { "action": { "search": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2612,7 +2959,7 @@ "label": "" }, "manageLog": { - "label": "" + "label": "Naplók megtekintése" }, "manageTask": { "label": "" @@ -2624,7 +2971,7 @@ "label": "Névjegy" }, "homeBoard": { - "label": "" + "label": "Főoldal" }, "preferences": { "label": "Saját preferenciák" @@ -2650,7 +2997,7 @@ } }, "group": { - "title": "", + "title": "Csoportok", "children": { "action": { "detail": { @@ -2684,12 +3031,12 @@ "label": "" }, "description": { - "label": "" + "label": "Leírás" } }, "page": { "list": { - "title": "", + "title": "Keresőmotorok", "noResults": { "title": "", "action": "" @@ -2713,11 +3060,11 @@ "title": "", "notification": { "success": { - "title": "", + "title": "A módosítások sikeresen alkalmazva", "message": "" }, "error": { - "title": "", + "title": "Nem sikerült alkalmazni a változtatásokat", "message": "" } }, @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/it.json b/packages/translation/src/lang/it.json index 4977d9f87..ac76933f4 100644 --- a/packages/translation/src/lang/it.json +++ b/packages/translation/src/lang/it.json @@ -1,73 +1,178 @@ { + "init": { + "step": { + "start": { + "title": "Ti diamo il benvenuto su Homarr", + "subtitle": "Iniziamo con la creazione della tua istanza di Homarr.", + "description": "Per iniziare, seleziona come vuoi configurare la tua istanza di Homarr.", + "action": { + "scratch": "Inizia da zero", + "importOldmarr": "Importa da Homarr prima della 1.0" + } + }, + "import": { + "title": "Importa dati", + "subtitle": "Puoi importare dati da un'istanza Homarr esistente.", + "dropzone": { + "title": "Trascina il file zip qui o fai clic per sfogliare", + "description": "Lo zip caricato sarà elaborato e sarai in grado di selezionare quello che vuoi importare" + }, + "fileInfo": { + "action": { + "change": "Cambia file" + } + }, + "importSettings": { + "title": "Importa impostazioni", + "description": "Configura le azioni d'importazione" + }, + "boardSelection": { + "title": "Trovate {count} board", + "description": "Scegli tutte le board con la dimensione che vuoi importare", + "action": { + "selectAll": "Seleziona tutto", + "unselectAll": "Deseleziona tutto" + } + }, + "summary": { + "title": "Riepilogo", + "description": "Nel riepilogo sottostante puoi vedere cosa verrà importato", + "action": { + "import": "Conferma importazione e continua" + }, + "entities": { + "apps": "Applicazioni", + "boards": "Board", + "integrations": "Integrazioni", + "credentialUsers": "Credential users" + } + }, + "tokenModal": { + "title": "Inserisci il token d'importazione", + "field": { + "token": { + "label": "Token", + "description": "Inserisci il token d'importazione mostrato dalla tua precedente istanza homarr" + } + }, + "notification": { + "error": { + "title": "Token non valido", + "message": "Token inserito non valido" + } + } + } + }, + "user": { + "title": "Amministratore", + "subtitle": "Specifica le credenziali per l'amministratore.", + "notification": { + "success": { + "title": "Utente creato", + "message": "L'utente è stato creato correttamente" + }, + "error": { + "title": "Creazione dell'utente non riuscita" + } + } + }, + "group": { + "title": "Gruppo esterno", + "subtitle": "Specifica il gruppo da utilizzare per gli utenti esterni.", + "form": { + "name": { + "label": "Nome gruppo", + "description": "Il nome deve corrispondere al gruppo admin del provider esterno" + } + } + }, + "settings": { + "title": "Impostazioni", + "subtitle": "Configura le impostazioni del server." + }, + "finish": { + "title": "Termina configurazione", + "subtitle": "È tutto pronto per iniziare!", + "description": "Hai completato con successo la configurazione. Ora puoi iniziare a usare Homarr. Seleziona la prossima azione:", + "action": { + "goToBoard": "Vai alla board: {name}", + "createBoard": "Crea la tua prima board", + "inviteUser": "Invita altri utenti", + "docs": "Leggi la documentazione" + } + } + }, + "backToStart": "Torna all'inizio" + }, "user": { "title": "Utenti", "name": "Utente", "page": { "login": { - "title": "", - "subtitle": "" + "title": "Accedi al tuo account", + "subtitle": "Felice di rivederti! Inserisci le tue credenziali" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "Unisciti ad Homarr", + "subtitle": "Ti diamo il benvenuto su Homarr! Crea il tuo account", + "description": "Hai ricevuto un invito da {username}" }, "init": { - "title": "", - "subtitle": "" + "title": "Nuova installazione di Homarr", + "subtitle": "Crea l'utenza amministrativa iniziale" } }, "field": { "email": { "label": "E-mail", - "verified": "" + "verified": "Verificato" }, "username": { "label": "Nome utente" }, "password": { - "label": "", + "label": "Password", "requirement": { - "length": "", + "length": "Include almeno 8 caratteri", "lowercase": "Include lettera minuscola", "uppercase": "Include lettera maiuscola", "number": "Include numero", - "special": "" + "special": "Include un simbolo speciale" } }, "passwordConfirm": { "label": "Conferma password" }, "previousPassword": { - "label": "" + "label": "Password precedente" }, "homeBoard": { - "label": "" + "label": "Home board" }, "pingIconsEnabled": { - "label": "" + "label": "Usa le icone per i ping" } }, "error": { - "usernameTaken": "" + "usernameTaken": "Nome utente già in uso" }, "action": { "login": { "label": "Accedi", - "labelWith": "", + "labelWith": "Accedi con {provider}", "notification": { "success": { - "title": "", - "message": "" + "title": "Accesso completato", + "message": "Hai effettuato l'accesso" }, "error": { - "title": "", - "message": "" + "title": "Login fallito", + "message": "Accesso non riuscito" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "Password dimenticata?", + "description": "Un amministratore può utilizzare il seguente comando per reimpostare la password:" } }, "register": { @@ -75,27 +180,37 @@ "notification": { "success": { "title": "Account creato", - "message": "" + "message": "Accedi per continuare" }, "error": { - "title": "", - "message": "" + "title": "Creazione dell’account non riuscita", + "message": "Il tuo account non può essere creato" } } }, "create": "Crea utente", "changePassword": { - "label": "", + "label": "Cambia password", "notification": { "success": { - "message": "" + "message": "Password modificata" }, "error": { - "message": "" + "message": "Impossibile cambiare la password" } } }, "changeHomeBoard": { + "notification": { + "success": { + "message": "Home board modificata con successo" + }, + "error": { + "message": "Impossibile cambiare la home board" + } + } + }, + "changeDefaultSearchEngine": { "notification": { "success": { "message": "" @@ -108,48 +223,48 @@ "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "Primo giorno della settimana cambiato" }, "error": { - "message": "" + "message": "Impossibile modificare il primo giorno della settimana" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "Icone ping modificate con successo" }, "error": { - "message": "" + "message": "Impossibile attivare o disattivare le icone di ping" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Cambia immagine", "notification": { "success": { - "message": "" + "message": "Immagine cambiata con successo" }, "error": { - "message": "" + "message": "Impossibile cambiare immagine" }, "toLarge": { - "title": "", - "message": "" + "title": "Immagine troppo grande", + "message": "La dimensione massima dell'immagine è {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Rimuovi immagine", + "confirm": "Vuoi davvero rimuovere l'immagine?", "notification": { "success": { - "message": "" + "message": "Immagine rimossa" }, "error": { - "message": "" + "message": "Impossibile rimuovere immagine" } } } @@ -157,278 +272,279 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "Profilo aggiornato" }, "error": { - "message": "" + "message": "Impossibile aggiornare il profilo" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "Elimina utente definitivamente", + "description": "Elimina questo utente, comprese le sue preferenze. Non eliminerà nessuna board. L'utente non verrà avvisato.", + "confirm": "Hai la certezza di voler eliminare l'utente {username} con le sue preferenze?" }, "select": { - "label": "", - "notFound": "" + "label": "Seleziona utente", + "notFound": "Nessun utente trovato" }, "transfer": { - "label": "" + "label": "Seleziona nuovo proprietario" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "Gruppi", + "name": "Gruppo", + "search": "Trova un gruppo", "field": { "name": "Nome", - "members": "" + "members": "Membri" }, "permission": { "admin": { - "title": "", + "title": "Amministratore", "item": { "admin": { - "label": "", - "description": "" + "label": "Amministratore", + "description": "I membri con questo permesso hanno pieno accesso a tutte le funzionalità e impostazioni" } } }, "app": { - "title": "", + "title": "Applicazioni", "item": { "create": { - "label": "", - "description": "" + "label": "Creare app", + "description": "Consenti ai membri di creare app" }, "use-all": { - "label": "", - "description": "" + "label": "Utilizzare tutte le app", + "description": "Consenti ai membri di aggiungere qualsiasi app alle loro board" }, "modify-all": { - "label": "", - "description": "" + "label": "Modificare tutte le app", + "description": "Consenti ai membri di modificare tutte le app" }, "full-all": { - "label": "", - "description": "" + "label": "Accesso completo all'app", + "description": "Consenti ai membri di gestire, utilizzare ed eliminare qualsiasi app" } } }, "board": { - "title": "", + "title": "Board", "item": { "create": { - "label": "", - "description": "" + "label": "Creare board", + "description": "Consenti ai membri di creare board" }, "view-all": { - "label": "", - "description": "" + "label": "Visualizzare tutte le board", + "description": "Consenti ai membri di visualizzare tutte le schede" }, "modify-all": { - "label": "", - "description": "" + "label": "Modificare tutte le schede", + "description": "Consenti ai membri di modificare tutte le schede (non include il controllo degli accessi e la danger zone)" }, "full-all": { - "label": "", - "description": "" + "label": "Accesso completo alla scheda", + "description": "Consenti ai membri di visualizzare, modificare ed eliminare tutte le schede (incluso il controllo degli accessi e la zona pericolosa)" } } }, "integration": { - "title": "", + "title": "Integrazioni", "item": { "create": { - "label": "", - "description": "" + "label": "Creare integrazioni", + "description": "Consenti ai membri di creare integrazioni" }, "use-all": { - "label": "", - "description": "" + "label": "Utilizzare tutte le integrazioni", + "description": "Consente ai membri di aggiungere qualsiasi integrazione alle loro schede" }, "interact-all": { - "label": "", - "description": "" + "label": "Interagire con qualsiasi integrazione", + "description": "Consenti ai membri di interagire con qualsiasi integrazione" }, "full-all": { - "label": "", - "description": "" + "label": "Accesso completo integrativo", + "description": "Consenti ai membri di gestire, utilizzare e interagire con qualsiasi integrazione" } } }, "media": { - "title": "", + "title": "Media", "item": { "upload": { - "label": "", - "description": "" + "label": "Caricare i media", + "description": "Consenti ai membri di caricare contenuti multimediali" }, "view-all": { - "label": "", - "description": "" + "label": "Visualizzare tutti i media", + "description": "Consenti ai membri di visualizzare tutti i media" }, "full-all": { - "label": "", - "description": "" + "label": "Accesso completo ai media", + "description": "Consenti ai membri di gestire ed eliminare qualsiasi contenuto multimediale" } } }, "other": { - "title": "", + "title": "Altro", "item": { "view-logs": { - "label": "", - "description": "" + "label": "Visualizza log", + "description": "Consentire ai membri di visualizzare i log" } } }, "search-engine": { - "title": "", + "title": "Motori di ricerca", "item": { "create": { - "label": "", - "description": "" + "label": "Creare motori di ricerca", + "description": "Consenti ai membri di creare motori di ricerca" }, "modify-all": { - "label": "", - "description": "" + "label": "Modificare tutti i motori di ricerca", + "description": "Consenti ai membri di modificare tutti i motori di ricerca" }, "full-all": { - "label": "", - "description": "" + "label": "Accesso completo al motore di ricerca", + "description": "Consenti ai membri di gestire ed eliminare qualsiasi motore di ricerca" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "Alcuni membri provengono da fornitori esterni e non possono essere gestiti qui", + "external": "Tutti i membri provengono da fornitori esterni e non possono essere gestiti qui" }, "reservedNotice": { - "message": "" + "message": "Questo gruppo è riservato all'uso del sistema e limita alcune azioni. " }, "action": { "create": { - "label": "", + "label": "Nuovo gruppo", "notification": { "success": { - "message": "" + "message": "Gruppo creato" }, "error": { - "message": "" + "message": "Impossibile creare il gruppo" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "Trasferisci ownership", + "description": "Trasferisci l'ownership di questo gruppo a un altro utente.", + "confirm": "Hai la certezza di voler trasferire l'ownership del gruppo {name} a {username}?", "notification": { "success": { - "message": "" + "message": "Gruppo {group} trasferito a {user}" }, "error": { - "message": "" + "message": "Impossibile trasferire l'ownership" } } }, "addMember": { - "label": "" + "label": "Aggiungi membro" }, "removeMember": { - "label": "", - "confirm": "" + "label": "Rimuovi membro", + "confirm": "Hai la certezza di voler rimuovere {user} da questo gruppo?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "Elimina gruppo", + "description": "Una volta eliminato un gruppo, non si può tornare indietro. Si prega di essere certi.", + "confirm": "Hai la certezza di voler eliminare il gruppo {name}?", "notification": { "success": { - "message": "" + "message": "Gruppo {name} eliminato" }, "error": { - "message": "" + "message": "Impossibile eliminare il gruppo {name}" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "Permessi salvati", + "message": "I permessi sono stati salvati" }, "error": { - "title": "", - "message": "" + "title": "Permessi non salvati", + "message": "I permessi non sono stati salvati" } } }, "update": { "notification": { "success": { - "message": "" + "message": "Il gruppo {name} è stato salvato" }, "error": { - "message": "" + "message": "Impossibile salvare il gruppo {name}" } } }, "select": { - "label": "", - "notFound": "" + "label": "Seleziona gruppo", + "notFound": "Nessun gruppo trovato" } } }, "app": { + "search": "", "page": { "list": { "title": "Applicazioni", "noResults": { - "title": "", - "action": "" + "title": "Non ci sono ancora app", + "action": "Crea la tua prima app" } }, "create": { - "title": "", + "title": "Nuova app", "notification": { "success": { - "title": "", - "message": "" + "title": "Creazione riuscita", + "message": "App creata" }, "error": { - "title": "", - "message": "" + "title": "Creazione fallita", + "message": "Impossibile creare l'app" } } }, "edit": { - "title": "", + "title": "Modifica app", "notification": { "success": { - "title": "", - "message": "" + "title": "Modifiche applicate", + "message": "App salvata" }, "error": { - "title": "", - "message": "" + "title": "Impossibile applicare le modifiche", + "message": "Impossibile salvare l'app" } } }, "delete": { - "title": "", - "message": "", + "title": "Elimina app", + "message": "Hai la certezza di voler eliminare l'app {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "Eliminato", + "message": "App eliminata" }, "error": { - "title": "", - "message": "" + "title": "Eliminazione non riuscita", + "message": "Impossibile eliminare l'app" } } } @@ -438,65 +554,65 @@ "label": "Nome" }, "description": { - "label": "" + "label": "Descrizione" }, "url": { - "label": "" + "label": "Url" } }, "action": { "select": { - "label": "", - "notFound": "" + "label": "Seleziona App", + "notFound": "Nessuna app trovata" } } }, "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "Integrazioni", + "search": "Cerca integrazioni", "noResults": { - "title": "" + "title": "Non ci sono ancora integrazioni" } }, "create": { - "title": "", + "title": "Nuova integrazione di {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "Creazione riuscita", + "message": "L'integrazione è stata creata con successo" }, "error": { - "title": "", - "message": "" + "title": "Creazione fallita", + "message": "Non è stato possibile creare l'integrazione" } } }, "edit": { - "title": "", + "title": "Modifica integrazione {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "Modifiche applicate", + "message": "L'integrazione è stata salvata correttamente" }, "error": { - "title": "", - "message": "" + "title": "Impossibile applicare le modifiche", + "message": "Non è stato possibile salvare l'integrazione" } } }, "delete": { - "title": "", - "message": "", + "title": "Elimina integrazione", + "message": "Hai la certezza di voler eliminare l'integrazione {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "Eliminato", + "message": "L'integrazione è stata eliminata correttamente" }, "error": { - "title": "", - "message": "" + "title": "Eliminazione non riuscita", + "message": "Impossibile eliminare l'integrazione" } } } @@ -506,88 +622,96 @@ "label": "Nome" }, "url": { - "label": "" + "label": "Url" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { - "create": "" + "create": "Nuova integrazione" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "Prova la connessione e crea", + "edit": "Prova la connessione e salva" }, - "alertNotice": "", + "alertNotice": "Il pulsante Salva è abilitato una volta stabilita una connessione con successo", "notification": { "success": { - "title": "", - "message": "" + "title": "Connessione riuscita", + "message": "La connessione è stata stabilita con successo" }, "invalidUrl": { "title": "URL invalido", - "message": "" + "message": "L'URL non è valido" }, "secretNotDefined": { - "title": "", - "message": "" + "title": "Credenziali mancanti", + "message": "Non tutte le credenziali sono state fornite" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "Credenziali non valide", + "message": "Le credenziali non sono valide" }, "commonError": { - "title": "", - "message": "" + "title": "Connessione fallita", + "message": "La connessione non è stata stabilita" }, "badRequest": { - "title": "", - "message": "" + "title": "Bad request", + "message": "La richiesta era malformata" }, "unauthorized": { - "title": "", - "message": "" + "title": "Non Autorizzato", + "message": "Probabilmente le credenziali sono sbagliate" }, "forbidden": { - "title": "", - "message": "" + "title": "Forbidden", + "message": "Probabilmente mancano i permessi" }, "notFound": { - "title": "", - "message": "" + "title": "Not found", + "message": "Probabilmente url o percorso errati" }, "internalServerError": { - "title": "", - "message": "" + "title": "Errore server interno", + "message": "Il server ha riscontrato un errore" }, "serviceUnavailable": { - "title": "", - "message": "" + "title": "Il servizio non è disponibile", + "message": "Il server non è attualmente disponibile" }, "connectionAborted": { - "title": "", - "message": "" + "title": "Connessione interrotta", + "message": "La connessione è stata interrotta" }, "domainNotFound": { - "title": "", - "message": "" + "title": "Dominio non trovato", + "message": "Il dominio non è stato trovato" }, "connectionRefused": { - "title": "", - "message": "" + "title": "Connessione rifiutata", + "message": "La connessione è stata rifiutata" }, "invalidJson": { - "title": "", - "message": "" + "title": "JSON non valido", + "message": "La risposta non era un JSON valido" }, "wrongPath": { - "title": "", - "message": "" + "title": "Percorso sbagliato", + "message": "Il percorso probabilmente non è corretto" } } }, "secrets": { - "title": "", - "lastUpdated": "", + "title": "Secrets", + "lastUpdated": "Ultimo aggiornamento {date}", + "notSet": { + "label": "Nessun valore impostato", + "tooltip": "Il secret richiesto non è stato ancora impostato" + }, "secureNotice": "", "reset": { "title": "", @@ -615,11 +739,11 @@ "permission": { "use": "", "interact": "", - "full": "" + "full": "Accesso completo integrativo" } }, "media": { - "plural": "", + "plural": "Media", "search": "", "field": { "name": "Nome", @@ -678,6 +802,7 @@ "previous": "Precedente", "next": "Successivo", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Riprova", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Accedi", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "", @@ -744,12 +876,12 @@ }, "zod": { "errors": { - "default": "Questo campo non è valido", - "required": "Questo campo è obbligatorio", + "default": "Campo non valido", + "required": "Campo obbligatorio", "string": { "startsWith": "Questo campo deve iniziare con {startsWith}", "endsWith": "Questo campo deve terminare con {endsWith}", - "includes": "Questo campo deve includere {includes}", + "includes": "Questo campo deve contenere {includes}", "invalidEmail": "" }, "tooSmall": { @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -860,7 +995,7 @@ }, "field": { "integrations": { - "label": "" + "label": "Integrazioni" }, "customCssClasses": { "label": "" @@ -911,10 +1046,10 @@ "label": "", "option": { "row": { - "label": "" + "label": "Orizzontale" }, "column": { - "label": "" + "label": "Verticale" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Bloccati oggi", "dnsQueriesToday": "Query di oggi", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Blocco note", "description": "", @@ -1050,9 +1205,9 @@ "controls": { "bold": "Grassetto", "italic": "Corsivo", - "strikethrough": "Testo barrato", + "strikethrough": "Barrato", "underline": "Sottolineato", - "colorText": "Testo a colori", + "colorText": "Colore testo", "colorHighlight": "Testo evidenziato colorato", "code": "Codice", "clear": "Rimuovi formattazione", @@ -1062,7 +1217,7 @@ "horizontalLine": "Linea orizzontale", "bulletList": "Elenco puntato", "orderedList": "Elenco ordinato", - "checkList": "Elenco di controllo", + "checkList": "Checklist", "increaseIndent": "Aumenta indentatura", "decreaseIndent": "Diminuisci indentatura", "link": "", @@ -1070,7 +1225,7 @@ "image": "Incorpora immagine", "addTable": "Aggiungi tabella", "deleteTable": "Elimina tabella", - "colorCell": "Colore cella", + "colorCell": "Colora Cella", "mergeCell": "Attiva/disattiva unione celle", "addColumnLeft": "Aggiungi colonna prima", "addColumnRight": "Aggiungi colonna dopo", @@ -1081,7 +1236,7 @@ }, "align": { "left": "Sinistra", - "center": "Centra", + "center": "Centro", "right": "Destra" }, "popover": { @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Il tuo browser non supporta iframes. Aggiorna il tuo browser." } }, @@ -1154,7 +1310,7 @@ "description": "", "option": { "displayName": { - "label": "Visualizza nome" + "label": "Nome visualizzato" }, "automationId": { "label": "ID automazione" @@ -1186,7 +1342,7 @@ }, "weather": { "name": "Meteo", - "description": "Mostra le informazioni meteo attuali di una località.", + "description": "Mostra le attuali informazioni meteo di un luogo.", "option": { "isFormatFahrenheit": { "label": "" @@ -1218,7 +1374,7 @@ "rain": "Pioggia", "freezingRain": "Pioggia gelata", "snowFall": "Neve", - "snowGrains": "Neve tonda", + "snowGrains": "Grandine", "rainShowers": "Rovesci", "snowShowers": "Forti nevicate", "thunderstorm": "Temporale", @@ -1227,21 +1383,21 @@ } }, "indexerManager": { - "name": "Stato del gestore dell'indicizzatore", + "name": "Stato dell'index manager", "description": "", "option": { "openIndexerSiteInNewTab": { "label": "" } }, - "title": "Gestore dell'indicizzatore", - "testAll": "Prova Tutto", + "title": "Index manager", + "testAll": "Prova tutto", "error": { "internalServerError": "" } }, "healthMonitoring": { - "name": "Monitoraggio dello stato del sistema", + "name": "Monitoraggio Salute di Sistema", "description": "Visualizza informazioni sulla salute e stato dei tuoi sistemi.", "option": { "fahrenheit": { @@ -1304,21 +1460,18 @@ "description": "" }, "app": { - "noData": "", + "noData": "Nessuna app trovata", "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, "option": {} }, "video": { - "name": "Flusso Video", - "description": "Incorpora un flusso video o un video da una videocamera o da un sito web", + "name": "Stream Video", + "description": "Incorpora uno stream video o un video da una videocamera o da un sito web", "option": { "feedUrl": { "label": "URL del feed" @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1486,7 +1644,7 @@ }, "mediaRequests-requestList": { "name": "", - "description": "Vedi un elenco di tutte le richieste multimediali dalla tua istanza Overseerr o Jellyseerr", + "description": "Visualizza un elenco di tutte le richieste media dalla tua istanza Overseerr o Jellyseerr", "option": { "linksTargetNewTab": { "label": "Apri i link in nuova scheda" @@ -1508,11 +1666,11 @@ }, "mediaRequests-requestStats": { "name": "", - "description": "Statistiche sulle richieste multimediali", + "description": "Statistiche sulle richieste dei media", "option": {}, "titles": { "stats": { - "main": "Statistiche Multimediali", + "main": "Statistiche Media", "approved": "Già approvato", "pending": "Approvazioni In Attesa", "processing": "", @@ -1523,11 +1681,70 @@ "total": "Totale" }, "users": { - "main": "Utenti Top", + "main": "Top Utenti", "requests": "" } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "Vista predefinita" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "Workers", + "queue": "Coda", + "statistics": "Statistiche" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "In coda", + "status": { + "healthy": "Normale funzionamento", + "unhealthy": "Compromesso" + } + }, + "panel": { + "statistics": { + "empty": "Vuoto", + "transcodes": "", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "Risoluzioni" + }, + "workers": { + "empty": "Vuoto", + "table": { + "file": "", + "eta": "", + "progress": "Avanzamento", + "transcode": "", + "healthCheck": "" + } + }, + "queue": { + "empty": "Vuoto", + "table": { + "file": "", + "size": "Dimensione", + "transcode": "", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Piccolo", "md": "Medio", @@ -1647,7 +1879,7 @@ "label": "" }, "backgroundImageAttachment": { - "label": "Allegato immagine di sfondo", + "label": "Immagine di background", "option": { "fixed": { "label": "", @@ -1681,7 +1913,7 @@ } }, "backgroundImageSize": { - "label": "Dimensioni dell'immagine di sfondo", + "label": "Dimensioni dell'immagine di background", "option": { "cover": { "label": "", @@ -1735,7 +1967,7 @@ "title": "" }, "background": { - "title": "Sfondo" + "title": "Background" }, "color": { "title": "" @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "Ti diamo il benvenuto su Homarr", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "Visualizzare tutte le schede", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1821,15 +2085,15 @@ "home": "", "boards": "", "apps": "Applicazioni", - "integrations": "", - "searchEngies": "", - "medias": "", + "integrations": "Integrazioni", + "searchEngies": "Motori di ricerca", + "medias": "Media", "users": { "label": "Utenti", "items": { "manage": "Gestisci", "invites": "Inviti", - "groups": "" + "groups": "Gruppi" } }, "tools": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1847,7 +2112,7 @@ "items": { "documentation": "Documentazione", "submitIssue": "", - "discord": "Discord della community", + "discord": "Community Discord", "sourceCode": "" } }, @@ -1860,9 +2125,9 @@ "board": "", "user": "Utenti", "invite": "Inviti", - "integration": "", + "integration": "Integrazioni", "app": "Applicazioni", - "group": "" + "group": "Gruppi" }, "statisticLabel": { "boards": "", @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Elimina definitivamente", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Generale", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Primo giorno della settimana", "accessibility": "Accessibilità" } @@ -1953,7 +2235,7 @@ "label": "Sicurezza" }, "groups": { - "label": "", + "label": "Gruppi", "title": "", "description": "" }, @@ -1961,10 +2243,10 @@ "label": "" }, "completed": { - "title": "" + "title": "Utente creato" }, "error": { - "title": "" + "title": "Creazione dell'utente non riuscita" } }, "action": { @@ -1977,7 +2259,7 @@ "action": { "new": { "title": "", - "description": "Dopo la scadenza, un invito non sarà più valido e il destinatario dell'invito non potrà creare un account." + "description": "Una volta scaduto, un invito non sarà più valido e il destinatario non potrà creare un account." }, "copy": { "title": "", @@ -1987,7 +2269,7 @@ }, "delete": { "title": "Elimina invito", - "description": "Siete sicuri di voler eliminare questo invito? Gli utenti con questo link non potranno più creare un account utilizzando tale link." + "description": "Hai la certezza di voler eliminare questo invito? Gli utenti con questo link non potranno più creare un account utilizzandolo." } }, "field": { @@ -2011,12 +2293,12 @@ "setting": { "general": { "title": "Generale", - "owner": "", + "owner": "Proprietario", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, "members": { - "title": "", + "title": "Membri", "search": "", "notFound": "" }, @@ -2081,12 +2363,20 @@ "board": { "title": "", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Aspetto", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Errore" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2125,7 +2418,7 @@ "label": "" }, "mediaServer": { - "label": "Server multimediale" + "label": "Media Server" }, "mediaOrganizer": { "label": "" @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2222,7 +2521,7 @@ "created": "Creato", "running": "In esecuzione", "paused": "In pausa", - "restarting": "Riavvio", + "restarting": "Riavvio in corso", "exited": "", "removing": "Rimozione in corso", "dead": "" @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2313,7 +2631,7 @@ }, "tab": { "user": "Utenti", - "group": "", + "group": "Gruppi", "inherited": "" }, "field": { @@ -2321,7 +2639,7 @@ "label": "Utente" }, "group": { - "label": "" + "label": "Gruppo" }, "permission": { "label": "" @@ -2339,7 +2657,7 @@ "label": "" }, "integrations": { - "label": "", + "label": "Integrazioni", "edit": { "label": "Modifica" }, @@ -2348,7 +2666,7 @@ } }, "search-engines": { - "label": "", + "label": "Motori di ricerca", "new": { "label": "" }, @@ -2357,7 +2675,7 @@ } }, "medias": { - "label": "" + "label": "Media" }, "apps": { "label": "Applicazioni", @@ -2377,7 +2695,7 @@ "security": "Sicurezza", "board": "", "groups": { - "label": "" + "label": "Gruppi" }, "invites": { "label": "Inviti" @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2446,7 +2770,7 @@ } }, "integration": { - "title": "" + "title": "Integrazioni" } } }, @@ -2501,11 +2825,16 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { "searchEngine": { - "title": "", + "title": "Motori di ricerca", "children": { "action": { "search": { @@ -2559,7 +2888,7 @@ "label": "" }, "discord": { - "label": "Discord della community" + "label": "Community Discord" } } } @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2612,7 +2959,7 @@ "label": "" }, "manageLog": { - "label": "" + "label": "Visualizza log" }, "manageTask": { "label": "" @@ -2650,7 +2997,7 @@ } }, "group": { - "title": "", + "title": "Gruppi", "children": { "action": { "detail": { @@ -2689,7 +3036,7 @@ }, "page": { "list": { - "title": "", + "title": "Motori di ricerca", "noResults": { "title": "", "action": "" @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/ja.json b/packages/translation/src/lang/ja.json index 970a14ad5..0936d82c1 100644 --- a/packages/translation/src/lang/ja.json +++ b/packages/translation/src/lang/ja.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "Homarrへようこそ", + "subtitle": "", + "description": "", + "action": { + "scratch": "ゼロからスタート", + "importOldmarr": "" + } + }, + "import": { + "title": "データのインポート", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "アプリ", + "boards": "ボード", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "トークン", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "設定", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "ユーザー", "name": "ユーザー", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "アプリ", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "アプリ", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -661,7 +785,7 @@ "error": "エラー", "action": { "add": "追加", - "apply": "適用する", + "apply": "適用", "backToOverview": "", "create": "作成", "edit": "編集", @@ -676,8 +800,9 @@ "confirm": "確認", "continue": "", "previous": "前へ", - "next": "次のページ", + "next": "次へ", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "リトライ", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "ログイン", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "危険な操作", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -908,13 +1043,13 @@ "label": "" }, "layout": { - "label": "", + "label": "レイアウト", "option": { "row": { - "label": "" + "label": "水平" }, "column": { - "label": "" + "label": "垂直" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "今日のブロック", "dnsQueriesToday": "今日のクエリ", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "メモ帳", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "お使いのブラウザは iframe をサポートしていません。ブラウザを更新してください。" } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "デフォルト表示" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "ワーカー", + "queue": "キュー", + "statistics": "統計" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "処理待ち", + "status": { + "healthy": "正常", + "unhealthy": "異常" + } + }, + "panel": { + "statistics": { + "empty": "空", + "transcodes": "トランスコード", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "コーデック", + "videoContainers": "コンテナ", + "videoResolutions": "解像度" + }, + "workers": { + "empty": "空", + "table": { + "file": "ファイル", + "eta": "", + "progress": "進捗状況", + "transcode": "トランスコード", + "healthCheck": "" + } + }, + "queue": { + "empty": "空", + "table": { + "file": "ファイル", + "size": "サイズ", + "transcode": "トランスコード", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "小", "md": "中", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "永久削除", "confirm": { @@ -1923,7 +2198,14 @@ "title": "一般", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "週の初日", "accessibility": "アクセシビリティ" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "一般", - "owner": "", + "owner": "所有者", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "ボード", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "外観", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "エラー" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/ko.json b/packages/translation/src/lang/ko.json index 6403d0ac3..9b6a441b3 100644 --- a/packages/translation/src/lang/ko.json +++ b/packages/translation/src/lang/ko.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "앱", + "boards": "보드", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "토큰", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "설정", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "사용자", "name": "사용자", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "앱", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "앱", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "이전", "next": "다음", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "다시 시도", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "로그인", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "위험한 설정", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -908,13 +1043,13 @@ "label": "" }, "layout": { - "label": "", + "label": "레이아웃", "option": { "row": { - "label": "" + "label": "수평" }, "column": { - "label": "" + "label": "세로" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "", "dnsQueriesToday": "오늘 쿼리", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "노트북", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "브라우저가 iframe을 지원하지 않습니다. 브라우저를 업데이트하세요." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "", + "queue": "대기열", + "statistics": "" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "", + "status": { + "healthy": "", + "unhealthy": "" + } + }, + "panel": { + "statistics": { + "empty": "비어 있음", + "transcodes": "", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "" + }, + "workers": { + "empty": "비어 있음", + "table": { + "file": "", + "eta": "남은 시간", + "progress": "진행률", + "transcode": "", + "healthCheck": "" + } + }, + "queue": { + "empty": "비어 있음", + "table": { + "file": "", + "size": "크기", + "transcode": "", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "", "md": "", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "영구 삭제", "confirm": { @@ -1923,7 +2198,14 @@ "title": "일반", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "요일별 요일", "accessibility": "접근성" } @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "보드", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "모양", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "오류" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/lt.json b/packages/translation/src/lang/lt.json index 9888e0ef3..39152f032 100644 --- a/packages/translation/src/lang/lt.json +++ b/packages/translation/src/lang/lt.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "Programėlės", + "boards": "Lentos", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "Žetonas", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "Nustatymai", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "Vartotojai", "name": "Vartotojas", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "Programėlės", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "Programėlės", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "", "next": "", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Prisijungti", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -911,10 +1046,10 @@ "label": "", "option": { "row": { - "label": "" + "label": "Horizontalus" }, "column": { - "label": "" + "label": "Vertikalus" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Šiandien užblokuota", "dnsQueriesToday": "Užklausos šiandien", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Užrašai", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Jūsų naršyklė nepalaiko iframe. Atnaujinkite savo naršyklę." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "", + "queue": "", + "statistics": "" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "", + "status": { + "healthy": "", + "unhealthy": "" + } + }, + "panel": { + "statistics": { + "empty": "", + "transcodes": "", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "" + }, + "workers": { + "empty": "", + "table": { + "file": "", + "eta": "", + "progress": "", + "transcode": "", + "healthCheck": "" + } + }, + "queue": { + "empty": "", + "table": { + "file": "", + "size": "", + "transcode": "", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Mažas", "md": "Vidutinis", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Ištrinti visam laikui", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Bendras", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "", "accessibility": "" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Bendras", - "owner": "", + "owner": "Savininkas", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Lentos", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Išvaizda", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/lv.json b/packages/translation/src/lang/lv.json index c4901706e..8fbf5f407 100644 --- a/packages/translation/src/lang/lv.json +++ b/packages/translation/src/lang/lv.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "Importēt datus", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "Lietotnes", + "boards": "Dēļi", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "Atslēga", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "Iestatījumi", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "Lietotāji", "name": "Lietotājs", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "Lietotnes", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "Lietotnes", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "Iepriekšējais", "next": "Nākamais", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Mēģiniet vēlreiz", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Pieslēgties", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Bīstamā zona", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -908,13 +1043,13 @@ "label": "" }, "layout": { - "label": "", + "label": "Izkārtojums", "option": { "row": { - "label": "" + "label": "Horizontāli" }, "column": { - "label": "" + "label": "Vertikāli" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Šodien bloķēti", "dnsQueriesToday": "Pieprasījumi šodien", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Piezīmes", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Jūsu pārlūkprogramma neatbalsta iframe. Lūdzu, atjauniniet pārlūkprogrammu." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "", + "queue": "Rinda", + "statistics": "" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "", + "status": { + "healthy": "", + "unhealthy": "" + } + }, + "panel": { + "statistics": { + "empty": "Tukšs", + "transcodes": "", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "" + }, + "workers": { + "empty": "Tukšs", + "table": { + "file": "", + "eta": "", + "progress": "", + "transcode": "", + "healthCheck": "" + } + }, + "queue": { + "empty": "Tukšs", + "table": { + "file": "", + "size": "Lielums", + "transcode": "", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Mazs", "md": "Vidējs", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Neatgriezeniski dzēst", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Vispārīgi", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Nedēļas pirmā diena", "accessibility": "Piekļūstamība" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Vispārīgi", - "owner": "", + "owner": "Īpašnieks", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Dēļi", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Izskats", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Kļūda" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/nl.json b/packages/translation/src/lang/nl.json index c509c3ef4..9e7a90079 100644 --- a/packages/translation/src/lang/nl.json +++ b/packages/translation/src/lang/nl.json @@ -1,26 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "Welkom bij Homarr", + "subtitle": "Laten we beginnen met het opzetten van je Homarr instantie.", + "description": "Selecteer om te beginnen hoe je je Homarr instantie wilt instellen.", + "action": { + "scratch": "Vanaf nul beginnen", + "importOldmarr": "Importeren uit Homarr vóór 1.0" + } + }, + "import": { + "title": "Gegevens importeren", + "subtitle": "Je kunt gegevens importeren uit een bestaande Homarr instantie.", + "dropzone": { + "title": "Sleep het ZIP-bestand hierheen of klik om te bladeren", + "description": "De geüploade ZIP wordt verwerkt en je kunt selecteren wat je wilt importeren" + }, + "fileInfo": { + "action": { + "change": "Bestand veranderen" + } + }, + "importSettings": { + "title": "Instellingen importeren", + "description": "Het importgedrag configureren" + }, + "boardSelection": { + "title": "{count} borden gevonden", + "description": "Kies alle borden met hun grootte die je wilt importeren", + "action": { + "selectAll": "Alles selecteren", + "unselectAll": "Alles deselecteren" + } + }, + "summary": { + "title": "Overzicht importeren", + "description": "In het onderstaande overzicht kun je zien wat er wordt geïmporteerd", + "action": { + "import": "Import bevestigen en doorgaan" + }, + "entities": { + "apps": "Apps", + "boards": "Borden", + "integrations": "Integraties", + "credentialUsers": "Inloggegevens gebruikers" + } + }, + "tokenModal": { + "title": "Importeertoken invoeren", + "field": { + "token": { + "label": "Penning", + "description": "Voer het getoonde importeertoken van je vorige Homarr instantie in" + } + }, + "notification": { + "error": { + "title": "Ongeldig token", + "message": "Het ingevoerde token is ongeldig" + } + } + } + }, + "user": { + "title": "Beheerder gebruiker", + "subtitle": "Geef de inloggegevens op voor de administrator gebruiker.", + "notification": { + "success": { + "title": "Gebruiker aangemaakt", + "message": "De gebruiker is succesvol aangemaakt" + }, + "error": { + "title": "Gebruiker aanmaken mislukt" + } + } + }, + "group": { + "title": "Externe groep", + "subtitle": "Geef de groep op die moet worden gebruikt voor externe gebruikers.", + "form": { + "name": { + "label": "Groepsnaam", + "description": "De naam moet overeenkomen met de beheerdersgroep van de externe provider" + } + } + }, + "settings": { + "title": "Instellingen", + "subtitle": "Serverinstellingen configureren." + }, + "finish": { + "title": "Instellen voltooien", + "subtitle": "Je bent er klaar voor!", + "description": "Je hebt het installatieproces succesvol afgerond. Je kunt Homarr nu gaan gebruiken. Selecteer je volgende actie:", + "action": { + "goToBoard": "Ga naar {name} bord", + "createBoard": "Je eerste bord aanmaken", + "inviteUser": "Andere gebruikers uitnodigen", + "docs": "Lees de documentatie" + } + } + }, + "backToStart": "Terug naar start" + }, "user": { "title": "Gebruikers", "name": "Gebruiker", "page": { "login": { - "title": "", - "subtitle": "" + "title": "Log in op je account", + "subtitle": "Welkom terug! Voer je inloggegevens in" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "Deelnemen aan Homarr", + "subtitle": "Welkom bij Homarr! Maak een account aan", + "description": "Je bent uitgenodigd door {username}" }, "init": { - "title": "", - "subtitle": "" + "title": "Nieuwe Homarr installatie", + "subtitle": "Maak de eerste beheerdersgebruiker aan" } }, "field": { "email": { "label": "E-mail", - "verified": "" + "verified": "Geverifiëerd" }, "username": { "label": "Gebruikersnaam" @@ -28,46 +133,46 @@ "password": { "label": "Wachtwoord", "requirement": { - "length": "", + "length": "Bevat ten minste 8 tekens", "lowercase": "Inclusief kleine letter", "uppercase": "Inclusief hoofdletter", - "number": "Inclusief aantal", - "special": "" + "number": "Inclusief getal", + "special": "Inclusief speciaal teken" } }, "passwordConfirm": { "label": "Wachtwoord bevestigen" }, "previousPassword": { - "label": "" + "label": "Vorig wachtwoord" }, "homeBoard": { - "label": "" + "label": "Home-bord" }, "pingIconsEnabled": { - "label": "" + "label": "Gebruik iconen voor pings" } }, "error": { - "usernameTaken": "" + "usernameTaken": "Gebruikersnaam is al in gebruik" }, "action": { "login": { "label": "Inloggen", - "labelWith": "", + "labelWith": "Login met {provider}", "notification": { "success": { - "title": "", - "message": "" + "title": "Login succesvol", + "message": "Je bent nu ingelogd" }, "error": { - "title": "", - "message": "" + "title": "Login mislukt", + "message": "Je login is mislukt" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "Wachtwoord vergeten?", + "description": "Een beheerder kan het volgende commando gebruiken om je wachtwoord opnieuw in te stellen:" } }, "register": { @@ -75,27 +180,37 @@ "notification": { "success": { "title": "Account aangemaakt", - "message": "" + "message": "Login om door te gaan" }, "error": { - "title": "", - "message": "" + "title": "Account aanmaken mislukt", + "message": "Je account kon niet worden aangemaakt" } } }, "create": "Gebruiker aanmaken", "changePassword": { - "label": "", + "label": "Wachtwoord wijzigen", "notification": { "success": { - "message": "" + "message": "Wachtwoord is succesvol gewijzigd" }, "error": { - "message": "" + "message": "Kan wachtwoord niet wijzigen" } } }, "changeHomeBoard": { + "notification": { + "success": { + "message": "Home-bord succesvol gewijzigd" + }, + "error": { + "message": "Kan startpagina niet wijzigen" + } + } + }, + "changeDefaultSearchEngine": { "notification": { "success": { "message": "" @@ -108,48 +223,48 @@ "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "Eerste dag van de week succesvol gewijzigd" }, "error": { - "message": "" + "message": "Kan eerste dag van week niet wijzigen" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "Ping-iconen succesvol omgeschakeld" }, "error": { - "message": "" + "message": "Ping-iconen kunnen niet worden omgeschakeld" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Afbeelding veranderen", "notification": { "success": { - "message": "" + "message": "De afbeelding is succesvol gewijzigd" }, "error": { - "message": "" + "message": "Kan afbeelding niet wijzigen" }, "toLarge": { - "title": "", - "message": "" + "title": "Afbeelding is te groot", + "message": "Maximale afbeeldingsgrootte is {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Afbeelding verwijderen", + "confirm": "Weet je zeker dat je de afbeelding wilt verwijderen?", "notification": { "success": { - "message": "" + "message": "Afbeelding succesvol verwijderd" }, "error": { - "message": "" + "message": "Kan afbeelding niet verwijderen" } } } @@ -157,63 +272,63 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "Profiel succesvol bijgewerkt" }, "error": { - "message": "" + "message": "Kan profiel niet bijwerken" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "Gebruiker permanent verwijderen", + "description": "Verwijdert deze gebruiker inclusief zijn voorkeuren. Verwijdert geen enkele borden. Gebruiker krijgt geen melding.", + "confirm": "Weet je zeker dat je de gebruiker {username} met zijn voorkeuren wilt verwijderen?" }, "select": { - "label": "", - "notFound": "" + "label": "Gebruiker selecteren", + "notFound": "Geen gebruiker gevonden" }, "transfer": { - "label": "" + "label": "Nieuwe eigenaar selecteren" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "Groepen", + "name": "Groep", + "search": "Vind een groep", "field": { "name": "Naam", - "members": "" + "members": "Leden" }, "permission": { "admin": { "title": "Beheerder", "item": { "admin": { - "label": "", - "description": "" + "label": "Beheerder", + "description": "Leden met deze machtiging hebben volledige toegang tot alle functies en instellingen" } } }, "app": { - "title": "", + "title": "Apps", "item": { "create": { - "label": "", - "description": "" + "label": "Apps aanmaken", + "description": "Laat leden apps aanmaken" }, "use-all": { - "label": "", - "description": "" + "label": "Alle apps gebruiken", + "description": "Laat leden apps aan hun borden toevoegen" }, "modify-all": { - "label": "", - "description": "" + "label": "Alle apps aanpassen", + "description": "Laat leden alle apps aanpassen" }, "full-all": { - "label": "", - "description": "" + "label": "Volledige app-toegang", + "description": "Laat leden elke app beheren, gebruiken en verwijderen" } } }, @@ -221,214 +336,215 @@ "title": "Borden", "item": { "create": { - "label": "", - "description": "" + "label": "Borden aanmaken", + "description": "Laat leden borden aanmaken" }, "view-all": { - "label": "", - "description": "" + "label": "Alle borden bekijken", + "description": "Laat leden alle borden bekijken" }, "modify-all": { - "label": "", - "description": "" + "label": "Alle borden aanpassen", + "description": "Laat leden alle borden wijzigen (exclusief toegangscontrole en gevarenzone)" }, "full-all": { - "label": "", - "description": "" + "label": "Toegang aan bord", + "description": "Laat leden alle borden bekijken, wijzigen en verwijderen (inclusief toegangscontrole en gevarenzone)" } } }, "integration": { - "title": "", + "title": "Integraties", "item": { "create": { - "label": "", - "description": "" + "label": "Integraties aanmaken", + "description": "Laat leden integraties aanmaken" }, "use-all": { - "label": "", - "description": "" + "label": "Alle integraties gebruiken", + "description": "Geeft leden de mogelijkheid om integraties toe te voegen aan hun borden" }, "interact-all": { - "label": "", - "description": "" + "label": "Interactie met elke integratie", + "description": "Laat leden communiceren met elke integratie" }, "full-all": { - "label": "", - "description": "" + "label": "Volledige integratietoegang", + "description": "Laat leden elke integratie te beheren, gebruiken en ermee werken" } } }, "media": { - "title": "", + "title": "Media", "item": { "upload": { - "label": "", - "description": "" + "label": "Media uploaden", + "description": "Laat leden media uploaden" }, "view-all": { - "label": "", - "description": "" + "label": "Alle media bekijken", + "description": "Laat leden alle media bekijken" }, "full-all": { - "label": "", - "description": "" + "label": "Volledige mediatoegang", + "description": "Laat leden alle media beheren en verwijderen" } } }, "other": { - "title": "", + "title": "Andere", "item": { "view-logs": { - "label": "", - "description": "" + "label": "Logs bekijken", + "description": "Laat leden logs bekijken" } } }, "search-engine": { - "title": "", + "title": "Zoekmachines", "item": { "create": { - "label": "", - "description": "" + "label": "Zoekmachines aanmaken", + "description": "Laat leden zoekmachines aanmaken" }, "modify-all": { - "label": "", - "description": "" + "label": "Alle zoekmachines aanpassen", + "description": "Laat leden alle zoekmachines aanpassen" }, "full-all": { - "label": "", - "description": "" + "label": "Volledige zoekmachinetoegang", + "description": "Laat leden elke zoekmachine beheren en verwijderen" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "Sommige leden zijn van externe providers en kunnen hier niet worden beheerd", + "external": "Alle leden zijn van externe providers en kunnen hier niet worden beheerd" }, "reservedNotice": { - "message": "" + "message": "Deze groep is gereserveerd voor systeemgebruik en beperkt sommige acties. " }, "action": { "create": { - "label": "", + "label": "Nieuwe groep", "notification": { "success": { - "message": "" + "message": "De groep is succesvol aangemaakt" }, "error": { - "message": "" + "message": "De groep kon niet worden aangemaakt" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "Eigendom overdragen", + "description": "Eigendom van deze groep overdragen aan een andere gebruiker.", + "confirm": "Weet je zeker dat je het eigendom voor de groep {name} wilt overdragen aan {username}?", "notification": { "success": { - "message": "" + "message": "Groep {group} succesvol overgezet naar {user}" }, "error": { - "message": "" + "message": "Kan eigendom niet overdragen" } } }, "addMember": { - "label": "" + "label": "Lid toevoegen" }, "removeMember": { - "label": "", - "confirm": "" + "label": "Lid verwijderen", + "confirm": "Weet je zeker dat je {user} uit deze groep wilt verwijderen?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "Groep verwijderen", + "description": "Als je eenmaal een groep hebt verwijderd, kun je niet meer terug. Wees er zeker van.", + "confirm": "Weet je zeker dat je de groep {name} wilt verwijderen?", "notification": { "success": { - "message": "" + "message": "Groep {name} succesvol verwijderd" }, "error": { - "message": "" + "message": "Kan groep {name} niet verwijderen" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "Machtigingen opgeslagen", + "message": "Machtigingen zijn succesvol opgeslagen" }, "error": { - "title": "", - "message": "" + "title": "Machtigingen niet opgeslagen", + "message": "Machtigingen zijn niet opgeslagen" } } }, "update": { "notification": { "success": { - "message": "" + "message": "De groep {name} is succesvol opgeslagen" }, "error": { - "message": "" + "message": "Kan groep {name} niet opslaan" } } }, "select": { - "label": "", - "notFound": "" + "label": "Groep selecteren", + "notFound": "Geen groep gevonden" } } }, "app": { + "search": "", "page": { "list": { - "title": "", + "title": "Apps", "noResults": { - "title": "", - "action": "" + "title": "Er zijn nog geen apps", + "action": "Je eerste app aanmaken" } }, "create": { - "title": "", + "title": "Nieuwe app", "notification": { "success": { - "title": "", - "message": "" + "title": "Succesvol aangemaakt", + "message": "De app is succesvol aangemaakt" }, "error": { - "title": "", - "message": "" + "title": "Aanmaken mislukt", + "message": "De app kon niet worden aangemaakt" } } }, "edit": { - "title": "", + "title": "App bewerken", "notification": { "success": { - "title": "", - "message": "" + "title": "Wijzigingen succesvol toegepast", + "message": "De app is succesvol opgeslagen" }, "error": { - "title": "", - "message": "" + "title": "Kan wijzigingen niet toepassen", + "message": "De app kon niet worden opgeslagen" } } }, "delete": { - "title": "", - "message": "", + "title": "App verwijderen", + "message": "Weet je zeker dat je de app {name} wilt verwijderen?", "notification": { "success": { - "title": "", - "message": "" + "title": "Succesvol verwijderd", + "message": "De app is succesvol verwijderd" }, "error": { - "title": "", - "message": "" + "title": "Verwijderen mislukt", + "message": "Kan de app niet verwijderen" } } } @@ -438,65 +554,65 @@ "label": "Naam" }, "description": { - "label": "" + "label": "Beschrijving" }, "url": { - "label": "" + "label": "URL" } }, "action": { "select": { - "label": "", - "notFound": "" + "label": "App selecteren", + "notFound": "Geen app gevonden" } } }, "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "Integraties", + "search": "Integraties zoeken", "noResults": { - "title": "" + "title": "Er zijn nog geen integraties" } }, "create": { - "title": "", + "title": "Nieuwe {name} integratie", "notification": { "success": { - "title": "", - "message": "" + "title": "Succesvol aangemaakt", + "message": "De integratie is succesvol aangemaakt" }, "error": { - "title": "", - "message": "" + "title": "Aanmaken mislukt", + "message": "De integratie kon niet worden aangemaakt" } } }, "edit": { - "title": "", + "title": "{name} integratie bewerken", "notification": { "success": { - "title": "", - "message": "" + "title": "Wijzigingen succesvol toegepast", + "message": "De integratie is succesvol opgeslagen" }, "error": { - "title": "", - "message": "" + "title": "Kan wijzigingen niet toepassen", + "message": "De integratie kon niet worden opgeslagen" } } }, "delete": { - "title": "", - "message": "", + "title": "Integratie verwijderen", + "message": "Weet je zeker dat je de integratie {name} wilt verwijderen?", "notification": { "success": { - "title": "", - "message": "" + "title": "Succesvol verwijderd", + "message": "De integratie is succesvol verwijderd" }, "error": { - "title": "", - "message": "" + "title": "Verwijderen mislukt", + "message": "Kan de integratie niet verwijderen" } } } @@ -506,105 +622,113 @@ "label": "Naam" }, "url": { - "label": "" + "label": "URL" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { - "create": "" + "create": "Nieuwe integratie" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "Verbinding testen en aanmaken", + "edit": "Verbinding testen en opslaan" }, - "alertNotice": "", + "alertNotice": "De opslaan knop wordt ingeschakeld zodra er een succesvolle verbinding tot stand is gebracht", "notification": { "success": { - "title": "", - "message": "" + "title": "Verbinding geslaagd", + "message": "De verbinding is tot stand gebracht" }, "invalidUrl": { "title": "Ongeldige URL", - "message": "" + "message": "De URL is ongeldig" }, "secretNotDefined": { - "title": "", - "message": "" + "title": "Ontbrekende inloggegevens", + "message": "Niet alle inloggegevens werden verstrekt" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "Ongeldige inloggegevens", + "message": "De inloggegevens zijn ongeldig" }, "commonError": { - "title": "", - "message": "" + "title": "Verbinding mislukt", + "message": "De verbinding kon niet tot stand worden gebracht" }, "badRequest": { - "title": "", - "message": "" + "title": "Bad request", + "message": "De aanvraag was onjuist" }, "unauthorized": { - "title": "", - "message": "" + "title": "Niet-geautoriseerd", + "message": "Waarschijnlijk verkeerde inloggegevens" }, "forbidden": { - "title": "", - "message": "" + "title": "Verboden", + "message": "Waarschijnlijk ontbrekende machtigingen" }, "notFound": { - "title": "", - "message": "" + "title": "Niet gevonden", + "message": "Waarschijnlijk verkeerde URL of pad" }, "internalServerError": { - "title": "", - "message": "" + "title": "Interne serverfout", + "message": "Er is een fout opgetreden bij de server" }, "serviceUnavailable": { - "title": "", - "message": "" + "title": "Service niet beschikbaar", + "message": "De server is momenteel niet beschikbaar" }, "connectionAborted": { - "title": "", - "message": "" + "title": "Verbinding afgebroken", + "message": "De verbinding is afgebroken" }, "domainNotFound": { - "title": "", - "message": "" + "title": "Domein niet gevonden", + "message": "Het domein kon niet worden gevonden" }, "connectionRefused": { - "title": "", - "message": "" + "title": "Verbinding geweigerd", + "message": "De verbinding werd geweigerd" }, "invalidJson": { - "title": "", - "message": "" + "title": "Ongeldige JSON", + "message": "Het antwoord was geen geldige JSON" }, "wrongPath": { - "title": "", - "message": "" + "title": "Verkeerde pad", + "message": "Het pad is waarschijnlijk niet juist" } } }, "secrets": { - "title": "", - "lastUpdated": "", - "secureNotice": "", + "title": "Geheimen", + "lastUpdated": "Laatst bijgewerkt {date}", + "notSet": { + "label": "Geen waarde ingesteld", + "tooltip": "Dit vereiste geheim is nog niet ingesteld" + }, + "secureNotice": "Dit geheim kan niet worden opgehaald na aanmaken", "reset": { - "title": "", - "message": "" + "title": "Geheim resetten", + "message": "Weet je zeker dat je dit geheim wilt resetten?" }, "noSecretsRequired": { - "segmentTitle": "", - "text": "" + "segmentTitle": "Geen geheimen", + "text": "Geen geheimen nodig voor deze integratie" }, "kind": { "username": { "label": "Gebruikersnaam", - "newLabel": "" + "newLabel": "Nieuwe gebruikersnaam" }, "apiKey": { - "label": "", - "newLabel": "" + "label": "API-sleutel", + "newLabel": "Nieuwe API-sleutel" }, "password": { "label": "Wachtwoord", @@ -613,14 +737,14 @@ } }, "permission": { - "use": "", - "interact": "", - "full": "" + "use": "Integraties selecteren in items", + "interact": "Interactie met integraties", + "full": "Volledige integratietoegang" } }, "media": { - "plural": "", - "search": "", + "plural": "Media", + "search": "Vind een media", "field": { "name": "Naam", "size": "Grootte", @@ -628,119 +752,127 @@ }, "action": { "upload": { - "label": "", - "file": "", + "label": "Media uploaden", + "file": "Bestand selecteren", "notification": { "success": { - "message": "" + "message": "De media is succesvol geüpload" }, "error": { - "message": "" + "message": "De media konden niet worden geüpload" } } }, "delete": { - "label": "", - "description": "", + "label": "Media verwijderen", + "description": "Weet je zeker dat je de media wilt verwijderen?", "notification": { "success": { - "message": "" + "message": "De media is succesvol verwijderd" }, "error": { - "message": "" + "message": "De media konden niet worden verwijderd" } } }, "copy": { - "label": "" + "label": "URL kopiëren" } } }, "common": { - "beta": "", + "beta": "Beta", "error": "Fout", "action": { "add": "Toevoegen", "apply": "Toepassen", - "backToOverview": "", + "backToOverview": "Terug naar overzicht", "create": "Aanmaken", - "edit": "Wijzigen", - "import": "", + "edit": "Bewerken", + "import": "Importeren", "insert": "Invoegen", "remove": "Verwijderen", "save": "Opslaan", "saveChanges": "Wijzigingen opslaan", "cancel": "Annuleren", "delete": "Verwijderen", - "discard": "", + "discard": "Negeren", "confirm": "Bevestigen", - "continue": "", + "continue": "Doorgaan", "previous": "Vorige", "next": "Volgende", - "checkoutDocs": "", - "tryAgain": "Probeer het opnieuw", - "loading": "" + "checkoutDocs": "De documentatie bekijken", + "checkLogs": "Controleer logs voor meer details", + "tryAgain": "Probeer opnieuw", + "loading": "Laden" }, - "here": "", + "here": "hier", "iconPicker": { - "label": "", - "header": "" + "label": "Icoon-URL", + "header": "Typ naam of objecten om te filteren op iconen… Homarr doorzoekt {countIcons} iconen voor je." + }, + "colorScheme": { + "options": { + "light": "Licht", + "dark": "Donker" + } }, "information": { - "min": "", - "max": "", - "days": "", + "min": "Min.", + "max": "Max.", + "days": "Dagen", "hours": "Uren", "minutes": "Minuten" }, "notification": { "create": { - "success": "", - "error": "" + "success": "Succesvol aangemaakt", + "error": "Aanmaken mislukt" }, "delete": { - "success": "", - "error": "" + "success": "Succesvol verwijderd", + "error": "Verwijderen mislukt" }, "update": { - "success": "", - "error": "" + "success": "Wijzigingen succesvol toegepast", + "error": "Kan wijzigingen niet toepassen" }, "transfer": { - "success": "", - "error": "" + "success": "Overdracht succesvol", + "error": "Overdracht mislukt" } }, "multiSelect": { - "placeholder": "" + "placeholder": "Kies één of meer waarden" }, "multiText": { - "placeholder": "", - "addLabel": "" + "placeholder": "Meer waarden toevoegen", + "addLabel": "{value} toevoegen" }, "select": { - "placeholder": "", + "placeholder": "Waarde kiezen", "badge": { - "recommended": "" + "recommended": "Aanbevolen" } }, "userAvatar": { "menu": { - "switchToDarkMode": "", - "switchToLightMode": "", - "management": "", + "switchToDarkMode": "Schakel naar donkere modus", + "switchToLightMode": "Schakel naar lichte modus", + "management": "Beheer", "preferences": "Jouw voorkeuren", - "logout": "", + "logout": "Uitloggen", "login": "Inloggen", - "homeBoard": "", - "loggedOut": "" + "homeBoard": "Je home-bord", + "loggedOut": "Uitgelogd", + "updateAvailable": "{countUpdates} updates beschikbaar: {tag}" } }, "dangerZone": "Gevarenzone", "noResults": "Geen resultaten gevonden", "preview": { - "show": "", - "hide": "" + "show": "Voorbeeld weergeven", + "hide": "Voorbeeld verbergen" }, "zod": { "errors": { @@ -748,12 +880,12 @@ "required": "Dit veld is verplicht", "string": { "startsWith": "Dit veld moet beginnen met {startsWith}", - "endsWith": "Dit veld moet eindigen op {endsWith}", + "endsWith": "Dit veld moet eindigen met {endsWith}", "includes": "Dit veld moet {includes} bevatten.", - "invalidEmail": "" + "invalidEmail": "Dit veld moet een geldig e-mailadres zijn" }, "tooSmall": { - "string": "Dit veld moet minstens {minimum} tekens lang zijn", + "string": "Dit veld moet minimaal {minimum} tekens lang zijn", "number": "Dit veld moet groter of gelijk zijn aan {minimum}" }, "tooBig": { @@ -761,12 +893,14 @@ "number": "Dit veld moet kleiner of gelijk zijn aan {maximum}" }, "custom": { - "passwordsDoNotMatch": "", - "passwordRequirements": "", - "boardAlreadyExists": "", - "invalidFileType": "", - "fileTooLarge": "", - "invalidConfiguration": "" + "passwordsDoNotMatch": "Wachtwoorden komen niet overeen", + "passwordRequirements": "Wachtwoord voldoet niet aan de eisen", + "boardAlreadyExists": "Er bestaat al een bord met deze naam", + "invalidFileType": "Ongeldig bestandstype, verwachtte {expected}", + "invalidFileName": "", + "fileTooLarge": "Bestand is te groot, maximale grootte is {maxSize}", + "invalidConfiguration": "Ongeldige configuratie", + "groupNameTaken": "Groepsnaam al in gebruik" } } } @@ -774,12 +908,12 @@ "section": { "dynamic": { "action": { - "create": "", - "remove": "" + "create": "Nieuwe dynamische sectie", + "remove": "Dynamische sectie verwijderen" }, "remove": { - "title": "", - "message": "" + "title": "Dynamische sectie verwijderen", + "message": "Weet je zeker dat je deze dynamische sectie wilt verwijderen? Items worden verplaatst naar dezelfde locatie in de bovenliggende sectie." } }, "category": { @@ -789,29 +923,29 @@ } }, "action": { - "create": "", - "edit": "", - "remove": "", + "create": "Nieuwe categorie", + "edit": "Categorie hernoemen", + "remove": "Categorie verwijderen", "moveUp": "Omhoog", "moveDown": "Omlaag", - "createAbove": "", - "createBelow": "" + "createAbove": "Nieuwe categorie hierboven", + "createBelow": "Nieuwe categorie hieronder" }, "create": { - "title": "", - "submit": "" + "title": "Nieuwe categorie", + "submit": "Categorie toevoegen" }, "remove": { - "title": "", - "message": "" + "title": "Categorie verwijderen", + "message": "Weet je zeker dat je de categorie {name} wilt verwijderen?" }, "edit": { - "title": "", - "submit": "" + "title": "Categorie hernoemen", + "submit": "Categorie hernoemen" }, "menu": { "label": { - "create": "", + "create": "Nieuwe categorie", "changePosition": "Positie wijzigen" } } @@ -819,12 +953,12 @@ }, "item": { "action": { - "create": "", - "import": "", - "edit": "", - "moveResize": "", - "duplicate": "", - "remove": "" + "create": "Nieuw item", + "import": "Item importeren", + "edit": "Item bewerken", + "moveResize": "Item verplaatsen / formaat wijzigen", + "duplicate": "Item dupliceren", + "remove": "Item verwijderen" }, "menu": { "label": { @@ -832,11 +966,12 @@ } }, "create": { - "title": "", - "addToBoard": "" + "title": "Kies een item om toe te voegen", + "search": "", + "addToBoard": "Toevoegen aan bord" }, "moveResize": { - "title": "", + "title": "Item verplaatsen / formaat wijzigen", "field": { "width": { "label": "Breedte" @@ -845,200 +980,220 @@ "label": "Hoogte" }, "xOffset": { - "label": "" + "label": "X offset" }, "yOffset": { - "label": "" + "label": "Y offset" } } }, "edit": { - "title": "", + "title": "Item bewerken", "advancedOptions": { - "label": "", - "title": "" + "label": "Geavanceerde opties", + "title": "Geavanceerde itemopties" }, "field": { "integrations": { - "label": "" + "label": "Integraties" }, "customCssClasses": { - "label": "" + "label": "Aangepaste CSS-classes" } } }, "remove": { - "title": "", - "message": "" + "title": "Item verwijderen", + "message": "Weet je zeker dat je dit item wilt verwijderen?" } }, "widget": { "app": { - "name": "", - "description": "", + "name": "App", + "description": "Een app insluiten op het bord.", "option": { "appId": { - "label": "" + "label": "App kiezen" }, "openInNewTab": { - "label": "Open in nieuw tabblad" + "label": "In nieuw tabblad openen" }, "showTitle": { - "label": "" + "label": "App naam weergeven" }, "showDescriptionTooltip": { - "label": "" + "label": "Beschrijving tooltip weergeven" }, "pingEnabled": { - "label": "" + "label": "Eenvoudige ping inschakelen" } }, "error": { "notFound": { - "label": "", - "tooltip": "" + "label": "Geen app", + "tooltip": "Je hebt geen geldige app geselecteerd" } } }, "bookmarks": { + "name": "Bladwijzers", + "description": "Toont meerdere app-links", + "option": { + "title": { + "label": "Titel" + }, + "layout": { + "label": "Lay-out", + "option": { + "row": { + "label": "Horizontaal" + }, + "column": { + "label": "Verticaal" + }, + "grid": { + "label": "Raster" + } + } + }, + "items": { + "label": "Bladwijzers", + "add": "Bladwijzer toevoegen" + } + } + }, + "dnsHoleSummary": { + "name": "DNS-hole overzicht", + "description": "Toont het overzicht van je DNS-hole", + "option": { + "layout": { + "label": "Lay-out", + "option": { + "row": { + "label": "Horizontaal" + }, + "column": { + "label": "Verticaal" + }, + "grid": { + "label": "Raster" + } + } + }, + "usePiHoleColors": { + "label": "Gebruik Pi-Hole kleuren" + } + }, + "error": { + "internalServerError": "DNS-hole overzicht ophalen mislukt", + "integrationsDisconnected": "Geen gegevens beschikbaar, alle integraties verbroken" + }, + "data": { + "adsBlockedToday": "Vandaag geblokkeerd", + "adsBlockedTodayPercentage": "Vandaag geblokkeerd", + "dnsQueriesToday": "Aanvragen vandaag", + "domainsBeingBlocked": "Domeinen op blokkadelijst" + }, + "domainsTooltip": "" + }, + "dnsHoleControls": { + "name": "DNS-hole bedieningen", + "description": "Bedien PiHole of AdGuard vanaf je dashboard", + "option": { + "layout": { + "label": "Lay-out", + "option": { + "row": { + "label": "Horizontaal" + }, + "column": { + "label": "Verticaal" + }, + "grid": { + "label": "Raster" + } + } + }, + "showToggleAllButtons": { + "label": "Alles omschakelen knoppen weergeven" + } + }, + "error": { + "internalServerError": "DNS-hole besturen mislukt" + }, + "controls": { + "enableAll": "Alles inschakelen", + "disableAll": "Alles uitschakelen", + "setTimer": "Timer instellen", + "set": "Instellen", + "enabled": "Ingeschakeld", + "disabled": "Uitgeschakeld", + "processing": "Verwerken", + "disconnected": "Verbinding verbroken", + "hours": "Uren", + "minutes": "Minuten", + "unlimited": "Laat leeg voor onbeperkt" + } + }, + "clock": { + "name": "Datum en tijd", + "description": "Toont de huidige datum en tijd.", + "option": { + "customTitleToggle": { + "label": "Aangepaste titel-/plaatsweergave", + "description": "Aangepaste titel of de naam van de stad/het land boven de klok weergeven." + }, + "customTitle": { + "label": "Titel" + }, + "is24HourFormat": { + "label": "24-uursnotatie", + "description": "Gebruik de 24-uursnotatie in plaats van de 12-uursnotatie" + }, + "showSeconds": { + "label": "Seconden weergeven" + }, + "useCustomTimezone": { + "label": "Gebruik een vaste tijdzone" + }, + "timezone": { + "label": "Tijdzone", + "description": "Kies de tijdzone volgens de IANA-standaard" + }, + "showDate": { + "label": "De datum weergeven" + }, + "dateFormat": { + "label": "Datumnotatie", + "description": "Hoe de datum eruit moet zien" + } + } + }, + "minecraftServerStatus": { "name": "", "description": "", "option": { "title": { "label": "" }, - "layout": { - "label": "", - "option": { - "row": { - "label": "" - }, - "column": { - "label": "" - }, - "grid": { - "label": "" - } - } + "domain": { + "label": "" }, - "items": { - "label": "", - "add": "" - } - } - }, - "dnsHoleSummary": { - "name": "", - "description": "", - "option": { - "layout": { - "label": "Indeling", - "option": { - "row": { - "label": "Horizontaal" - }, - "column": { - "label": "Verticaal" - }, - "grid": { - "label": "" - } - } - }, - "usePiHoleColors": { + "isBedrockServer": { "label": "" } }, - "error": { - "internalServerError": "", - "integrationsDisconnected": "" - }, - "data": { - "adsBlockedToday": "Vandaag geblokkeerd", - "adsBlockedTodayPercentage": "Vandaag geblokkeerd", - "dnsQueriesToday": "Queries vandaag", - "domainsBeingBlocked": "" - } - }, - "dnsHoleControls": { - "name": "", - "description": "Bedien PiHole of AdGuard vanaf je dashboard", - "option": { - "layout": { - "label": "Indeling", - "option": { - "row": { - "label": "Horizontaal" - }, - "column": { - "label": "Verticaal" - }, - "grid": { - "label": "" - } - } - }, - "showToggleAllButtons": { - "label": "" - } - }, - "error": { - "internalServerError": "" - }, - "controls": { - "enableAll": "", - "disableAll": "", - "setTimer": "", - "set": "Instellen", - "enabled": "Ingeschakeld", - "disabled": "Uitgeschakeld", - "processing": "", - "disconnected": "", - "hours": "Uren", - "minutes": "Minuten", - "unlimited": "" - } - }, - "clock": { - "name": "", - "description": "Toont de huidige datum en tijd.", - "option": { - "customTitleToggle": { - "label": "", - "description": "" - }, - "customTitle": { - "label": "" - }, - "is24HourFormat": { - "label": "", - "description": "" - }, - "showSeconds": { - "label": "" - }, - "useCustomTimezone": { - "label": "" - }, - "timezone": { - "label": "Tijdzone", - "description": "" - }, - "showDate": { - "label": "" - }, - "dateFormat": { - "label": "", - "description": "" - } + "status": { + "online": "", + "offline": "" } }, "notebook": { "name": "Notitieboek", - "description": "", + "description": "Een eenvoudige notitie widget die markdown ondersteunt", "option": { "showToolbar": { - "label": "Toon de werkbalk om je te helpen markdown te schrijven" + "label": "De werkbalk weergeven om je te helpen markdown te schrijven" }, "allowReadOnlyCheck": { "label": "Controle in alleen-lezen modus toestaan" @@ -1052,28 +1207,28 @@ "italic": "Schuingedrukt", "strikethrough": "Doorgestreept", "underline": "Onderstreept", - "colorText": "Kleur tekst", + "colorText": "Tekstkleur", "colorHighlight": "Gekleurde tekst markeren", - "code": "", + "code": "Code", "clear": "Opmaak wissen", "heading": "Koptekst {level}", "align": "Tekst uitlijnen: {position}", "blockquote": "Blokquote", "horizontalLine": "Horizontale lijn", "bulletList": "Opsommingslijst", - "orderedList": "Geordende lijst", + "orderedList": "Gerangschikte lijst", "checkList": "Controlelijst", - "increaseIndent": "Inspringen vergroten", + "increaseIndent": "Inspringing vergroten", "decreaseIndent": "Inspringen verminderen", - "link": "", + "link": "Link", "unlink": "Link verwijderen", "image": "Afbeelding insluiten", "addTable": "Tabel toevoegen", "deleteTable": "Tabel verwijderen", - "colorCell": "Kleur cel", - "mergeCell": "Cellen samenvoegen togglen", - "addColumnLeft": "Kolom toevoegen vóór", - "addColumnRight": "Kolom toevoegen ná", + "colorCell": "Celkleur", + "mergeCell": "Cellen samenvoegen schakelen", + "addColumnLeft": "Kolom ervoor toevoegen", + "addColumnRight": "Kolom erna toevoegen", "deleteColumn": "Kolom verwijderen", "addRowTop": "Rij toevoegen vóór", "addRowBelow": "Rij toevoegen ná", @@ -1095,8 +1250,8 @@ } }, "iframe": { - "name": "", - "description": "Insluiten van alle inhoud van het internet. Sommige websites kunnen de toegang beperken.", + "name": "iFrame", + "description": "Elke inhoud van het internet insluiten. Sommige websites kunnen de toegang beperken.", "option": { "embedUrl": { "label": "URL insluiten" @@ -1127,31 +1282,32 @@ } }, "error": { - "noUrl": "", + "noUrl": "Geen iFrame URL opgegeven", + "unsupportedProtocol": "", "noBrowerSupport": "Je browser ondersteunt geen iframes. Update je browser." } }, "smartHome-entityState": { - "name": "", - "description": "", + "name": "Entiteitsstatus", + "description": "Status van een entiteit weergeven en optioneel omschakelen", "option": { "entityId": { - "label": "Entiteit-ID" + "label": "Entiteits-ID" }, "displayName": { - "label": "" + "label": "Weergavenaam" }, "entityUnit": { - "label": "" + "label": "Entiteitseenheid" }, "clickable": { - "label": "" + "label": "Klikbaar" } } }, "smartHome-executeAutomation": { - "name": "", - "description": "", + "name": "Automatisering uitvoeren", + "description": "Activeer een automatisering met één klik", "option": { "displayName": { "label": "Weergavenaam" @@ -1161,26 +1317,26 @@ } }, "spotlightAction": { - "run": "" + "run": "{name} uitvoeren" } }, "calendar": { "name": "Kalender", - "description": "", + "description": "Gebeurtenissen van je integraties weergeven in een kalenderweergave binnen een bepaalde relatieve tijdsperiode", "option": { "releaseType": { - "label": "", + "label": "Radarr uitgavetype", "options": { - "inCinemas": "", - "digitalRelease": "", - "physicalRelease": "" + "inCinemas": "In bioscopen", + "digitalRelease": "Digitale uitgave", + "physicalRelease": "Fysieke uitgave" } }, "filterPastMonths": { - "label": "" + "label": "Start vanaf" }, "filterFutureMonths": { - "label": "" + "label": "Eindig bij" } } }, @@ -1189,28 +1345,28 @@ "description": "Toont de huidige weersinformatie van een ingestelde locatie.", "option": { "isFormatFahrenheit": { - "label": "" + "label": "Temperatuur in fahrenheit" }, "location": { - "label": "Weerslocatie" + "label": "Weerlocatie" }, "showCity": { - "label": "" + "label": "Stad weergeven" }, "hasForecast": { - "label": "" + "label": "Weersverwachting weergeven" }, "forecastDayCount": { - "label": "", - "description": "" + "label": "Aantal weersverwachting-dagen", + "description": "Als de widget niet breed genoeg is, worden er minder dagen getoond" }, "dateFormat": { - "label": "", - "description": "" + "label": "Datumnotatie", + "description": "Hoe de datum eruit moet zien" } }, "kind": { - "clear": "Helder", + "clear": "Wissen", "mainlyClear": "Overwegend helder", "fog": "Mist", "drizzle": "Motregen", @@ -1227,17 +1383,17 @@ } }, "indexerManager": { - "name": "Indexeer beheerder status", - "description": "", + "name": "Indexeringsbeheerder status", + "description": "Status van je indexers", "option": { "openIndexerSiteInNewTab": { - "label": "" + "label": "Indexersite in nieuw tabblad openen" } }, - "title": "Indexeer beheerder", + "title": "Indexeringsbeheerder", "testAll": "Alles testen", "error": { - "internalServerError": "" + "internalServerError": "Indexersstatus ophalen mislukt" } }, "healthMonitoring": { @@ -1258,41 +1414,41 @@ } }, "popover": { - "information": "", - "processor": "", - "memory": "", - "memoryAvailable": "", - "version": "", - "uptime": "", - "loadAverage": "", - "minute": "", - "minutes": "", - "used": "", + "information": "Informatie", + "processor": "Processor: {cpuModelName}", + "memory": "Geheugen: {memory}GiB", + "memoryAvailable": "Beschikbaar: {memoryAvailable}GiB ({percent}%)", + "version": "Versie: {version}", + "uptime": "Uptime: {months} maanden, {days} dagen, {hours} uren, {minutes} minuten", + "loadAverage": "Gemiddelde belasting:", + "minute": "1 minuut", + "minutes": "{count} minuten", + "used": "Gebruikt", "available": "Beschikbaar", - "lastSeen": "" + "lastSeen": "Laatste statusupdate: {lastSeen}" }, "memory": {}, "error": { - "internalServerError": "" + "internalServerError": "Gezondheidsstatus ophalen mislukt" } }, "common": { "location": { - "query": "", - "latitude": "", - "longitude": "", - "disabledTooltip": "", - "unknownLocation": "", + "query": "Stad / postcode", + "latitude": "Breedtegraad", + "longitude": "Lengtegraad", + "disabledTooltip": "Voer een stad of postcode in", + "unknownLocation": "Onbekende locatie", "search": "Zoeken", "table": { "header": { - "city": "", - "country": "", - "coordinates": "", - "population": "" + "city": "Stad", + "country": "Land", + "coordinates": "Coördinaten", + "population": "Populatie" }, "action": { - "select": "" + "select": "{city}, {countryCode} selecteren" }, "population": { "fallback": "Onbekend" @@ -1300,265 +1456,328 @@ } }, "integration": { - "noData": "", - "description": "" + "noData": "Geen integratie gevonden", + "description": "Klik om een nieuwe integratie aan te maken" }, "app": { - "noData": "", - "description": "" + "noData": "Geen app gevonden", + "description": "Klik om een nieuwe app aan te maken" }, "error": { - "action": { - "logs": "" - }, - "noIntegration": "", - "noData": "" + "noIntegration": "Geen integratie geselecteerd", + "noData": "Geen integratiegegevens beschikbaar" }, "option": {} }, "video": { "name": "Video stream", - "description": "Een videostream of video van een camera of een website insluiten", + "description": "Een videostream of video van een camera of website insluiten", "option": { "feedUrl": { - "label": "" + "label": "Feed-URL" }, "hasAutoPlay": { "label": "Automatisch afspelen", - "description": "" + "description": "Automatisch afspelen werkt alleen als het gedempt is vanwege browserbeperkingen" }, "isMuted": { - "label": "" + "label": "Gedempt" }, "hasControls": { - "label": "" + "label": "Besturingen weergeven" } }, "error": { - "noUrl": "", - "forYoutubeUseIframe": "" + "noUrl": "Geen video-URL opgegeven", + "forYoutubeUseIframe": "Voor YouTube video's gebruik je de iframe-optie" } }, "mediaServer": { - "name": "", - "description": "", - "option": {} + "name": "Huidige mediaserver streams", + "description": "De huidige streams op je mediaservers weergeven", + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { - "name": "", - "description": "", + "name": "Client downloaden", + "description": "Geeft je de mogelijkheid om downloads van torrent- en usenet-clients te bekijken en beheren.", "option": { "columns": { - "label": "" + "label": "Kolommen om te laten zien" }, "enableRowSorting": { - "label": "" + "label": "Items sorteren inschakelen" }, "defaultSort": { - "label": "" + "label": "Kolom die standaard wordt gebruikt voor sorteren" }, "descendingDefaultSort": { - "label": "" + "label": "Sorteren omkeren" }, "showCompletedUsenet": { - "label": "" + "label": "Usenet-items weergeven die zijn gemarkeerd als voltooid" }, "showCompletedTorrent": { - "label": "" + "label": "Torrentvermeldingen weergeven die zijn gemarkeerd als voltooid" }, "activeTorrentThreshold": { - "label": "" + "label": "Voltooide torrent verbergen onder deze drempel (in kiB/s)" }, "categoryFilter": { - "label": "" + "label": "Categorieën/labels om te filteren" }, "filterIsWhitelist": { - "label": "" + "label": "Filteren als witte lijst" }, "applyFilterToRatio": { - "label": "" + "label": "Gebruik filter om ratio te berekenen" } }, "errors": { - "noColumns": "", - "noCommunications": "" + "noColumns": "Kolommen selecteren in items", + "noCommunications": "Kan geen gegevens laden van integratie" }, "items": { "actions": { - "columnTitle": "" + "columnTitle": "Bedieningen" }, "added": { - "columnTitle": "", + "columnTitle": "Toegevoegd", "detailsTitle": "Datum toegevoegd" }, "category": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Extra’s", + "detailsTitle": "Categorieën (of extra informatie)" }, "downSpeed": { - "columnTitle": "", + "columnTitle": "Omlaag", "detailsTitle": "Downloadsnelheid" }, "index": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "#", + "detailsTitle": "Huidige index binnen client" }, "id": { - "columnTitle": "" + "columnTitle": "ID" }, "integration": { "columnTitle": "Integratie" }, "name": { - "columnTitle": "" + "columnTitle": "Taaknaam" }, "progress": { "columnTitle": "Voortgang", - "detailsTitle": "" + "detailsTitle": "Downloadvoortgang" }, "ratio": { "columnTitle": "Verhouding", - "detailsTitle": "" + "detailsTitle": "Torrent ratio (ontvangen/verzonden)" }, "received": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Totaal down", + "detailsTitle": "Totaal gedownload" }, "sent": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Totaal up", + "detailsTitle": "Totaal geüpload" }, "size": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Bestandsgrootte", + "detailsTitle": "Totale grootte van selectie/bestanden" }, "state": { "columnTitle": "Status", - "detailsTitle": "" + "detailsTitle": "Taakstatus" }, "time": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Eindtijd", + "detailsTitle": "Tijd sinds/tot voltooiing" }, "type": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Type", + "detailsTitle": "Client type downloaden" }, "upSpeed": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Omhoog", + "detailsTitle": "Uploadsnelheid" } }, "states": { - "downloading": "Bezig met downloaden", + "downloading": "Downloaden", "queued": "In wachtrij", "paused": "Gepauzeerd", "completed": "Voltooid", - "failed": "", - "processing": "", - "leeching": "", - "stalled": "", + "failed": "Mislukt", + "processing": "Verwerken", + "leeching": "Leeching", + "stalled": "Stilgevallen", "unknown": "Onbekend", - "seeding": "" + "seeding": "Seeding" }, "actions": { "clients": { - "modalTitle": "", - "pause": "", - "resume": "" + "modalTitle": "Client lijst downloaden", + "pause": "Alle clients/items pauzeren", + "resume": "Alle clients/items hervatten" }, "client": { - "pause": "", - "resume": "" + "pause": "Client pauzeren", + "resume": "Client hervatten" }, "item": { - "pause": "", - "resume": "", + "pause": "Item pauzeren", + "resume": "Item hervatten", "delete": { - "title": "", - "modalTitle": "", - "entry": "", - "entryAndFiles": "" + "title": "Bestand verwijderen", + "modalTitle": "Weet je zeker dat je deze taak wilt verwijderen?", + "entry": "Item verwijderen", + "entryAndFiles": "Item en bestand(en) verwijderen" } } }, - "globalRatio": "" + "globalRatio": "Globale verhouding" }, "mediaRequests-requestList": { - "name": "", - "description": "Bekijk een lijst met alle mediaverzoeken van je Overseerr of Jellyseerr instantie", + "name": "Media-aanvragen lijst", + "description": "Bekijk een lijst met alle media-aanvragen van je Overseerr of Jellyseerr instantie", "option": { "linksTargetNewTab": { "label": "Links in nieuw tabblad openen" } }, "pending": { - "approve": "", - "approving": "", - "decline": "" + "approve": "Aanvraag goedkeuren", + "approving": "Aanvraag goedkeuren…", + "decline": "Aanvraag weigeren" }, "availability": { "unknown": "Onbekend", - "pending": "", - "processing": "", + "pending": "In afwachting", + "processing": "Verwerken", "partiallyAvailable": "Gedeeltelijk", "available": "Beschikbaar" }, - "toBeDetermined": "" + "toBeDetermined": "TBD" }, "mediaRequests-requestStats": { - "name": "", - "description": "Statistieken over je mediaverzoeken", + "name": "Media-aanvragen statistieken", + "description": "Statistieken over je media-aanvragen", "option": {}, "titles": { "stats": { - "main": "Media statistieken", + "main": "Mediastatistieken", "approved": "Reeds goedgekeurd", "pending": "In afwachting van goedkeuring", - "processing": "", - "declined": "", - "available": "", - "tv": "TV verzoeken", - "movie": "Film verzoeken", + "processing": "Wordt verwerkt", + "declined": "Reeds geweigerd", + "available": "Reeds beschikbaar", + "tv": "TV aanvragen", + "movie": "Film aanvragen", "total": "Totaal" }, "users": { "main": "Grootste gebruikers", - "requests": "" + "requests": "Aanvragen" + } + } + }, + "mediaTranscoding": { + "name": "Mediatranscodering", + "description": "Statistieken, huidige wachtrij en worker-status van je media transcodering", + "option": { + "defaultView": { + "label": "Standaardweergave" + }, + "queuePageSize": { + "label": "Wachtrij paginagrootte" + } + }, + "tab": { + "workers": "Workers", + "queue": "Wachtrij", + "statistics": "Statistieken" + }, + "currentIndex": "{start}-{end} van {total}", + "healthCheck": { + "title": "Gezondheidscontrole", + "queued": "In wachtrij", + "status": { + "healthy": "Gezond", + "unhealthy": "Niet-gezond" + } + }, + "panel": { + "statistics": { + "empty": "Leeg", + "transcodes": "Transcodes", + "transcodesCount": "Transcodes: {value}", + "healthChecksCount": "Gezondheidscontroles: {value}", + "filesCount": "Bestanden: {value}", + "savedSpace": "Bespaarde ruimte: {value}", + "healthChecks": "Gezondheidscontroles", + "videoCodecs": "Codecs", + "videoContainers": "Containers", + "videoResolutions": "Resoluties" + }, + "workers": { + "empty": "Leeg", + "table": { + "file": "Bestand", + "eta": "ETA", + "progress": "Voortgang", + "transcode": "Transcoderen", + "healthCheck": "Gezondheidscontrole" + } + }, + "queue": { + "empty": "Leeg", + "table": { + "file": "Bestand", + "size": "Grootte", + "transcode": "Transcoderen", + "healthCheck": "Gezondheidscontrole" + } } } }, "rssFeed": { - "name": "", - "description": "", + "name": "RSS-feeds", + "description": "Eén of meer algemene RSS-, ATOM- of JSON-feeds monitoren en weergeven", "option": { "feedUrls": { - "label": "" + "label": "Feed URL's" }, "enableRtl": { - "label": "" + "label": "RTL inschakelen" }, "textLinesClamp": { - "label": "" + "label": "Beschrijving regel-clamp" }, "maximumAmountPosts": { - "label": "" + "label": "Aantal berichtenlimiet" } } } }, "widgetPreview": { "toggle": { - "enabled": "", - "disabled": "" + "enabled": "Bewerkingsmodus ingeschakeld", + "disabled": "Bewerkingsmodus uitgeschakeld" }, "dimensions": { - "title": "" + "title": "Afmetingen wijzigen" } }, "board": { "action": { - "edit": { + "duplicate": { + "title": "", + "message": "", "notification": { "success": { "title": "", @@ -1568,62 +1787,75 @@ "title": "", "message": "" } + } + }, + "edit": { + "notification": { + "success": { + "title": "Wijzigingen succesvol toegepast", + "message": "Het bord is succesvol opgeslagen" + }, + "error": { + "title": "Kan wijzigingen niet toepassen", + "message": "Het bord kon niet worden opgeslagen" + } }, "confirmLeave": { - "title": "", - "message": "" + "title": "Niet-opgeslagen wijzigingen", + "message": "Je hebt niet-opgeslagen wijzigingen, weet je zeker dat je weg wilt?" } }, "oldImport": { - "label": "", + "label": "Importeren uit Homarr vóór 1.0.0", "notification": { "success": { - "title": "", - "message": "" + "title": "Succesvol geimporteerd", + "message": "Het bord is succesvol geïmporteerd" }, "error": { - "title": "", - "message": "" + "title": "Importeren mislukt", + "message": "Het bord kon niet worden geïmporteerd, controleer de logs voor meer informatie" } }, "form": { "file": { - "label": "", - "invalidError": "" + "label": "JSON-bestand selecteren", + "invalidError": "Ongeldig configuratiebestand" }, "apps": { - "label": "", + "label": "Apps", "avoidDuplicates": { - "label": "", - "description": "" + "label": "Duplicaten vermijden", + "description": "Negeert apps waar al een app met dezelfde href bestaat" }, "onlyImportApps": { - "label": "", - "description": "" + "label": "Alleen apps importeren", + "description": "Voegt alleen de apps toe, het bord moet handmatig opnieuw worden aangemaakt" } }, "name": { - "label": "" + "label": "Bord naam" }, "screenSize": { - "label": "", + "label": "Schermgrootte", + "description": "In versies vóór 1.0 bestonden drie verschillende modi, zodat je het aantal kolommen voor elke schermgrootte kon kiezen.", "option": { "sm": "Klein", - "md": "Middel", + "md": "Gemiddeld", "lg": "Groot" } }, "sidebarBehavior": { - "label": "", - "description": "", + "label": "Zijbalk-gedrag", + "description": "Zijbalken zijn verwijderd in 1.0, je kunt kiezen wat er moet gebeuren met de items erin.", "option": { "lastSection": { - "label": "", - "description": "" + "label": "Laatste sectie", + "description": "De zijbalk wordt onder de laatste sectie weergegeven" }, "removeItems": { - "label": "", - "description": "" + "label": "Items verwijderen", + "description": "Items in de zijbalk worden verwijderd" } } } @@ -1632,51 +1864,51 @@ }, "field": { "pageTitle": { - "label": "" + "label": "Paginatitel" }, "metaTitle": { - "label": "" + "label": "Meta titel" }, "logoImageUrl": { - "label": "" + "label": "Logo afbeeldings-URL" }, "faviconImageUrl": { - "label": "" + "label": "Favicon afbeeldings-URL" }, "backgroundImageUrl": { - "label": "" + "label": "Achtergrondafbeelding URL" }, "backgroundImageAttachment": { "label": "Achtergrondafbeelding bijlage", "option": { "fixed": { - "label": "", - "description": "" + "label": "Vastgezet", + "description": "Achtergrond blijft op dezelfde positie." }, "scroll": { - "label": "", - "description": "" + "label": "Scrollen", + "description": "Achtergrond scrolt met je muis." } } }, "backgroundImageRepeat": { - "label": "", + "label": "Achtergrondafbeelding herhalen", "option": { "repeat": { - "label": "", - "description": "" + "label": "Herhalen", + "description": "De afbeelding wordt zoveel herhaald als nodig is om het hele achtergrondafbeelding gebied te bedekken." }, "no-repeat": { - "label": "", - "description": "" + "label": "Niet herhalen", + "description": "De afbeelding wordt niet herhaald en vult mogelijk niet de hele ruimte." }, "repeat-x": { - "label": "", - "description": "" + "label": "X herhalen", + "description": "Hetzelfde als ‘herhaal', maar alleen op de horizontale as." }, "repeat-y": { - "label": "", - "description": "" + "label": "Y herhalen", + "description": "Hetzelfde als ‘herhaal', maar alleen op de verticale as." } } }, @@ -1684,12 +1916,12 @@ "label": "Achtergrondafbeelding grootte", "option": { "cover": { - "label": "", - "description": "" + "label": "Bedekken", + "description": "Schaalt de afbeelding zo klein mogelijk om het hele venster te bedekken door overtollige ruimte bij te snijden." }, "contain": { - "label": "", - "description": "" + "label": "Insluiten", + "description": "Schaalt de afbeelding zo groot mogelijk binnen de container zonder de afbeelding bij te snijden of uit te rekken." } } }, @@ -1700,61 +1932,61 @@ "label": "Secundaire kleur" }, "opacity": { - "label": "" + "label": "Dekking" }, "customCss": { - "label": "", + "label": "Aangepaste CSS voor dit bord", "description": "Pas je dashboard verder aan met behulp van CSS, alleen aanbevolen voor ervaren gebruikers", "customClassesAlert": { - "title": "", - "description": "" + "title": "Aangepaste classes", + "description": "Je kunt aangepaste classes toevoegen aan je borditems in de geavanceerde opties van elk item en ze gebruiken in de aangepaste CSS hierboven." } }, "columnCount": { - "label": "" + "label": "Kolom aantal" }, "name": { "label": "Naam" }, "isPublic": { "label": "Openbaar", - "description": "" + "description": "Openbare borden zijn voor iedereen toegankelijk, zelfs zonder account." } }, "content": { - "metaTitle": "" + "metaTitle": "{boardName} bord" }, "setting": { - "title": "", + "title": "Instellingen voor {boardName} bord", "section": { "general": { "title": "Algemeen", - "unrecognizedLink": "" + "unrecognizedLink": "De opgegeven link wordt niet herkend en geeft geen voorbeeld, maar werkt misschien nog wel." }, "layout": { - "title": "Indeling" + "title": "Lay-out" }, "background": { "title": "Achtergrond" }, "color": { - "title": "" + "title": "Kleuren" }, "customCss": { - "title": "" + "title": "Aangepaste CSS" }, "access": { - "title": "", + "title": "Toegangsbeheer", "permission": { "item": { "view": { "label": "Bord bekijken" }, "modify": { - "label": "" + "label": "Bord aanpassen" }, "full": { - "label": "" + "label": "Volledige toegang" } } } @@ -1763,92 +1995,125 @@ "title": "Gevarenzone", "action": { "rename": { - "label": "", - "description": "", - "button": "", + "label": "Bord hernoemen", + "description": "Als je de naam verandert, worden alle links naar dit bord verbroken.", + "button": "Naam wijzigen", "modal": { - "title": "" + "title": "Bord hernoemen" } }, "visibility": { - "label": "", + "label": "Bord-zichtbaarheid wijzigen", "description": { - "public": "", - "private": "" + "public": "Dit bord is momenteel openbaar.", + "private": "Dit bord is momenteel privé." }, "button": { - "public": "", - "private": "" + "public": "Privé maken", + "private": "Openbaar maken" }, "confirm": { "public": { - "title": "", - "description": "" + "title": "Bord privé maken", + "description": "Weet je zeker dat je dit bord privé wilt maken? Dit verbergt het bord voor het publiek. Links voor gastgebruikers worden verbroken." }, "private": { - "title": "", - "description": "" + "title": "Bord openbaar maken", + "description": "Weet je zeker dat je dit bord openbaar wilt maken? Dit maakt het bord toegankelijk voor iedereen." } } }, "delete": { - "label": "", - "description": "", - "button": "", + "label": "Dit bord verwijderen", + "description": "Als je eenmaal een bord hebt verwijderd, kun je niet meer terug. Wees er zeker van.", + "button": "Dit bord verwijderen", "confirm": { "title": "Bord verwijderen", - "description": "" + "description": "Weet je zeker dat je dit bord wilt verwijderen? Hiermee verwijder je het bord en alle inhoud definitief." } } } } } + }, + "error": { + "noBoard": { + "title": "Welkom bij Homarr", + "description": "Een strak, modern dashboard waarmee je al je apps en diensten binnen handbereik hebt.", + "link": "Je eerste bord aanmaken", + "notice": "Om deze pagina te laten verdwijnen, maak je een bord aan en stel je het in als home-bord" + }, + "notFound": { + "title": "Bord niet gevonden", + "description": "Het opgegeven bord is niet gevonden of je hebt er geen toegang toe.", + "link": "Alle borden bekijken", + "notice": "Controleer de link of neem contact op met een beheerder als je denkt dat deze toegankelijk moet zijn" + }, + "homeBoard": { + "title": "Geen home-bord", + "admin": { + "description": "Je hebt nog geen home-bord ingesteld voor de server.", + "link": "Serverwijd home-bord configureren", + "notice": "Om deze pagina voor alle gebruikers te laten verdwijnen, stel je een home-bord in voor de server" + }, + "user": { + "description": "Je hebt nog geen home-bord ingesteld.", + "link": "Je home-bord configureren", + "notice": "Om deze pagina te laten verdwijnen, geef je het home-bord op in je voorkeuren" + }, + "anonymous": { + "description": "De serverbeheerder heeft nog geen home-bord ingesteld.", + "link": "Openbare borden bekijken", + "notice": "Om deze pagina te laten verdwijnen, vraag je de serverbeheerder om een home-bord in te stellen voor de server" + } + } } }, "management": { - "metaTitle": "", + "metaTitle": "Beheer", "title": { - "morning": "", - "afternoon": "", - "evening": "" + "morning": "Goedemorgen, {username}", + "afternoon": "Goedemiddag, {username}", + "evening": "Goedenavond, {username}" }, "notFound": { - "title": "", - "text": "" + "title": "Niet gevonden", + "text": "Kon de aangevraagde bron niet vinden" }, "navbar": { "items": { - "home": "", + "home": "Home", "boards": "Borden", - "apps": "", - "integrations": "", - "searchEngies": "", - "medias": "", + "apps": "Apps", + "integrations": "Integraties", + "searchEngies": "Zoekmachines", + "medias": "Media", "users": { "label": "Gebruikers", "items": { "manage": "Beheren", "invites": "Uitnodigingen", - "groups": "" + "groups": "Groepen" } }, "tools": { "label": "Gereedschappen", "items": { - "docker": "", - "logs": "", - "api": "", - "tasks": "" + "docker": "Docker", + "logs": "Logs", + "api": "API", + "certificates": "", + "tasks": "Taken" } }, "settings": "Instellingen", "help": { - "label": "", + "label": "Help", "items": { "documentation": "Documentatie", - "submitIssue": "", - "discord": "", - "sourceCode": "" + "submitIssue": "Een probleem melden", + "discord": "Community Discord", + "sourceCode": "Broncode" } }, "about": "Over" @@ -1860,47 +2125,57 @@ "board": "Borden", "user": "Gebruikers", "invite": "Uitnodigingen", - "integration": "", - "app": "", - "group": "" + "integration": "Integraties", + "app": "Apps", + "group": "Groepen" }, "statisticLabel": { "boards": "Borden", - "resources": "", - "authentication": "", - "authorization": "" + "resources": "Bronnen", + "authentication": "Authenticatie", + "authorization": "Authorisatie" } }, "board": { "title": "Jouw borden", "action": { "new": { - "label": "" + "label": "Nieuw bord" }, "open": { - "label": "" + "label": "Bord openen" }, "settings": { "label": "Instellingen" }, "setHomeBoard": { + "label": "Instellen als je home-bord", + "badge": { + "label": "Home", + "tooltip": "Dit bord wordt weergegeven als je home-bord" + } + }, + "setMobileHomeBoard": { "label": "", "badge": { "label": "", "tooltip": "" } }, + "duplicate": { + "label": "" + }, "delete": { "label": "Permanent verwijderen", "confirm": { "title": "Bord verwijderen", - "description": "" + "description": "Weet je zeker dat je het {name} bord wilt verwijderen?" } } }, "visibility": { - "public": "", - "private": "" + "public": "Dit bord is openbaar", + "private": "Dit bord is privé" }, "modal": { "createBoard": { @@ -1913,17 +2188,24 @@ } }, "media": { - "includeFromAllUsers": "" + "includeFromAllUsers": "Media opnemen van alle gebruikers" }, "user": { - "back": "", - "fieldsDisabledExternalProvider": "", + "back": "Terug naar gebruikers", + "fieldsDisabledExternalProvider": "Bepaalde velden zijn uitgeschakeld omdat ze worden beheerd door een externe authenticatieprovider.", "setting": { "general": { "title": "Algemeen", "item": { - "language": "", - "board": "", + "language": "Taal & regio", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Eerste dag van de week", "accessibility": "Toegankelijkheid" } @@ -1940,50 +2222,50 @@ "title": "Gebruikers" }, "edit": { - "metaTitle": "" + "metaTitle": "Gebruiker {username} bewerken" }, "create": { "metaTitle": "Gebruiker aanmaken", - "title": "", + "title": "Nieuwe gebruiker aanmaken", "step": { "personalInformation": { - "label": "" + "label": "Persoonlijke gegevens" }, "security": { "label": "Beveiliging" }, "groups": { - "label": "", - "title": "", - "description": "" + "label": "Groepen", + "title": "Selecteer alle groepen waar gebruikers lid van moeten zijn", + "description": "De groep {everyoneGroup} wordt aan alle gebruikers toegewezen en kan niet worden verwijderd." }, "review": { - "label": "" + "label": "Beoordelen" }, "completed": { - "title": "" + "title": "Gebruiker aangemaakt" }, "error": { - "title": "" + "title": "Gebruiker aanmaken mislukt" } }, "action": { - "createAnother": "", - "back": "" + "createAnother": "Andere gebruiker aanmaken", + "back": "Terug naar de gebruikerslijst" } }, "invite": { "title": "Gebruikersuitnodigingen beheren", "action": { "new": { - "title": "", + "title": "Nieuwe uitnodiging", "description": "Na de vervaldatum is een uitnodiging niet langer geldig en kan de ontvanger van de uitnodiging geen account meer aanmaken." }, "copy": { - "title": "", - "description": "", + "title": "Uitnodiging kopiëren", + "description": "Je uitnodiging is gegenereerd. Na het sluiten van dit venster kun je deze link niet meer kopiëren. Als je deze persoon niet langer wilt uitnodigen, kun je deze uitnodiging op elk moment verwijderen.", "link": "Uitnodigingslink", - "button": "" + "button": "Kopiëren en sluiten" }, "delete": { "title": "Uitnodiging verwijderen", @@ -1992,7 +2274,7 @@ }, "field": { "id": { - "label": "" + "label": "ID" }, "creator": { "label": "Maker" @@ -2007,23 +2289,23 @@ } }, "group": { - "back": "", + "back": "Terug naar groepen", "setting": { "general": { "title": "Algemeen", - "owner": "", - "ownerOfGroup": "", - "ownerOfGroupDeleted": "" + "owner": "Eigenaar", + "ownerOfGroup": "Eigenaar van deze groep", + "ownerOfGroupDeleted": "De eigenaar van deze groep is verwijderd. Het heeft momenteel geen eigenaar." }, "members": { - "title": "", - "search": "", - "notFound": "" + "title": "Leden", + "search": "Vind een lid", + "notFound": "Geen leden gevonden" }, "permissions": { - "title": "", + "title": "Machtigingen", "form": { - "unsavedChanges": "" + "unsavedChanges": "Er zijn niet-opgeslagen wijzigingen!" } } } @@ -2032,137 +2314,154 @@ "title": "Instellingen", "notification": { "success": { - "message": "" + "message": "Instellingen opgeslagen" }, "error": { - "message": "" + "message": "Instellingen opslaan mislukt" } }, "section": { "analytics": { - "title": "", + "title": "Analytics", "general": { - "title": "", - "text": "" + "title": "Anonieme analyses sturen", + "text": "Homarr verstuurt geanonimiseerde analyses met behulp van de open source software Umami. Het verzamelt nooit persoonlijke informatie en is daarom volledig GDPR & CCPA compliant. We moedigen je aan om analytics in te schakelen omdat het ons open source team helpt bij het identificeren van problemen en het prioriteren van onze backlog." }, "widgetData": { - "title": "", - "text": "" + "title": "Widgetgegevens", + "text": "Stuur welke widgets (en hun aantal) je hebt geconfigureerd. Bevat geen URL's, namen of andere gegevens." }, "integrationData": { - "title": "", - "text": "" + "title": "Integratiegegevens", + "text": "Stuur welke integraties (en het aantal) je hebt geconfigureerd. Bevat geen URL's, namen of andere gegevens." }, "usersData": { - "title": "", - "text": "" + "title": "Gebruikersgegevens", + "text": "Stuur het aantal gebruikers en of je SSO hebt geactiveerd" } }, "crawlingAndIndexing": { - "title": "", - "warning": "", + "title": "Crawlen en indexeren", + "warning": "Het in- of uitschakelen van instellingen hier heeft grote invloed op hoe zoekmachines je pagina zullen indexeren en crawlen. Elke instelling is een aanvraag en het is aan de crawler om deze instellingen toe te passen. Het kan meerdere dagen of weken duren voordat elke wijziging is toegepast. Sommige instellingen kunnen zoekmachinespecifiek zijn.", "noIndex": { - "title": "", - "text": "" + "title": "Geen index", + "text": "De website niet indexeren in zoekmachines en niet weergeven in zoekresultaten" }, "noFollow": { - "title": "", - "text": "" + "title": "Niet volgen", + "text": "Geen enkele links volgen tijdens het indexeren. Als je dit uitschakelt, zullen crawlers proberen alle links op Homarr te volgen." }, "noTranslate": { - "title": "", - "text": "" + "title": "Geen vertaling", + "text": "Als de taal van de site waarschijnlijk niet de taal is die de gebruiker wil lezen, zal Google een vertaallink tonen in de zoekresultaten" }, "noSiteLinksSearchBox": { - "title": "", - "text": "" + "title": "Geen sitelinks zoekvak", + "text": "Google bouwt een zoekvak met de gecrawlde links samen met andere directe links. Als je dit inschakelt, vraagt Google om dat vak uit te schakelen." } }, "board": { - "title": "", + "title": "Borden", "homeBoard": { + "label": "Globaal home-bord", + "mobileLabel": "", + "description": "Alleen openbare borden zijn beschikbaar voor selectie" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Weergave", "defaultColorScheme": { - "label": "", + "label": "Standaard kleurenschema", "options": { - "light": "", - "dark": "" + "light": "Licht", + "dark": "Donker" } } }, "culture": { - "title": "", + "title": "Cultuur", "defaultLocale": { - "label": "" + "label": "Standaard taal" } } } }, "tool": { "tasks": { - "title": "", + "title": "Taken", "status": { - "idle": "", + "idle": "Niet actief", "running": "Actief", "error": "Fout" }, "job": { - "iconsUpdater": { + "minecraftServerStatus": { "label": "" }, + "iconsUpdater": { + "label": "Icoon updater" + }, "analytics": { - "label": "" + "label": "Analytics" }, "smartHomeEntityState": { - "label": "" + "label": "Smart home entiteitstatus" }, "ping": { - "label": "" + "label": "Pings" }, "mediaServer": { - "label": "Media server" + "label": "Mediaserver" }, "mediaOrganizer": { - "label": "" + "label": "Media organisatoren" }, "downloads": { - "label": "" + "label": "Downloads" }, "mediaRequestStats": { - "label": "" + "label": "Media-aanvraag statistieken" }, "mediaRequestList": { - "label": "" + "label": "Media-aanvraag lijst" }, "rssFeeds": { - "label": "" + "label": "RSS-feeds" }, "indexerManager": { - "label": "" + "label": "Indexeringsbeheerder" }, "healthMonitoring": { - "label": "" + "label": "Gezondheidsmonitoring" }, "dnsHole": { - "label": "" + "label": "DNS-hole gegevens" }, "sessionCleanup": { - "label": "" + "label": "Sessie opruimen" + }, + "updateChecker": { + "label": "Update checker" + }, + "mediaTranscoding": { + "label": "Mediatranscodering" } } }, "api": { - "title": "", + "title": "API", "modal": { "createApiToken": { - "title": "", - "description": "", - "button": "" + "title": "API-token aangemaakt", + "description": "API-token is aangemaakt. Wees voorzichtig, dit token is versleuteld in de database en zal nooit meer aan jou worden overgedragen. Als je dit token verliest, kun je dit specifieke token niet meer opvragen.", + "button": "Kopiëren en sluiten" } }, "tab": { @@ -2170,15 +2469,15 @@ "label": "Documentatie" }, "apiKey": { - "label": "", - "title": "", + "label": "Authenticatie", + "title": "API-sleutels", "button": { - "createApiToken": "" + "createApiToken": "API-token aanmaken" }, "table": { "header": { - "id": "", - "createdBy": "" + "id": "ID", + "createdBy": "Aangemaakt door" } } } @@ -2186,31 +2485,31 @@ } }, "about": { - "version": "", - "text": "", + "version": "Versie {version}", + "text": "Homarr is een open source project dat wordt onderhouden door vrijwilligers. Dankzij deze mensen is Homarr sinds 2021 een groeiend project. Ons team werkt volledig op afstand vanuit veel verschillende landen aan Homarr in hun vrije tijd zonder compensatie.", "accordion": { "contributors": { - "title": "", - "subtitle": "" + "title": "Bijdragers", + "subtitle": "{count} onderhouden code & Homarr" }, "translators": { - "title": "", - "subtitle": "" + "title": "Vertalers", + "subtitle": "{count} bijdragen aan vertalingen in vele talen" }, "libraries": { - "title": "", - "subtitle": "" + "title": "Bibliotheken", + "subtitle": "{count} gebruikt in de code van Homarr" } } } } }, "docker": { - "title": "", + "title": "Containers", "table": { - "updated": "", - "search": "", - "selected": "" + "updated": "Bijgewerkt {when}", + "search": "Zoek {count} containers", + "selected": "{selectCount} van {totalCount} containers geselecteerd" }, "field": { "name": { @@ -2222,10 +2521,10 @@ "created": "Aangemaakt", "running": "Actief", "paused": "Gepauzeerd", - "restarting": "Bezig met herstarten", - "exited": "", - "removing": "Bezig met verwijderen", - "dead": "" + "restarting": "Herstarten", + "exited": "Verlaten", + "removing": "Verwijderen", + "dead": "Dood" } }, "containerImage": { @@ -2237,41 +2536,41 @@ }, "action": { "start": { - "label": "", + "label": "Start", "notification": { "success": { - "title": "", - "message": "" + "title": "Containers gestart", + "message": "De containers werden succesvol gestart" }, "error": { - "title": "", - "message": "" + "title": "Containers niet gestart", + "message": "De containers konden niet worden gestart" } } }, "stop": { - "label": "", + "label": "Stoppen", "notification": { "success": { - "title": "", - "message": "" + "title": "Containers gestopt", + "message": "De containers werden succesvol gestopt" }, "error": { - "title": "", - "message": "" + "title": "Containers niet gestopt", + "message": "De containers konden niet worden gestopt" } } }, "restart": { - "label": "Herstart", + "label": "Herstarten", "notification": { "success": { - "title": "", - "message": "" + "title": "Containers herstart", + "message": "De containers werden succesvol herstart" }, "error": { - "title": "", - "message": "" + "title": "Containers niet opnieuw opgestart", + "message": "De containers konden niet worden herstart" } } }, @@ -2279,16 +2578,29 @@ "label": "Verwijderen", "notification": { "success": { - "title": "", - "message": "" + "title": "Containers verwijderd", + "message": "De containers werden succesvol verwijderd" }, "error": { - "title": "", - "message": "" + "title": "Containers niet verwijderd", + "message": "De containers konden niet worden verwijderd" } } }, "refresh": { + "label": "Verversen", + "notification": { + "success": { + "title": "Containers ververst", + "message": "Je bekijkt nu de meest recente gegevens" + }, + "error": { + "title": "Containers worden niet ververst", + "message": "Er is iets misgegaan tijdens het verversen van de containers" + } + } + }, + "addToHomarr": { "label": "", "notification": { "success": { @@ -2299,37 +2611,43 @@ "title": "", "message": "" } + }, + "modal": { + "title": "" } } + }, + "error": { + "internalServerError": "Docker-containers zijn niet opgehaald" } }, "permission": { - "title": "", + "title": "Machtigingen", "userSelect": { - "title": "" + "title": "Gebruikersmachtiging toevoegen" }, "groupSelect": { - "title": "" + "title": "Groepsmachtiging toevoegen" }, "tab": { "user": "Gebruikers", - "group": "", - "inherited": "" + "group": "Groepen", + "inherited": "Geërfde groepen" }, "field": { "user": { "label": "Gebruiker" }, "group": { - "label": "" + "label": "Groep" }, "permission": { - "label": "" + "label": "Machtiging" } }, "action": { - "saveUser": "", - "saveGroup": "" + "saveUser": "Gebruikersmachtiging opslaan", + "saveGroup": "Groepsmachtiging opslaan" } }, "navigationStructure": { @@ -2339,33 +2657,33 @@ "label": "Borden" }, "integrations": { - "label": "", + "label": "Integraties", "edit": { - "label": "Wijzigen" + "label": "Bewerken" }, "new": { - "label": "" + "label": "Nieuw" } }, "search-engines": { - "label": "", + "label": "Zoekmachines", "new": { - "label": "" + "label": "Nieuw" }, "edit": { - "label": "Wijzigen" + "label": "Bewerken" } }, "medias": { - "label": "" + "label": "Media" }, "apps": { - "label": "", + "label": "Apps", "new": { - "label": "" + "label": "Nieuw" }, "edit": { - "label": "Wijzigen" + "label": "Bewerken" } }, "users": { @@ -2377,7 +2695,7 @@ "security": "Beveiliging", "board": "Borden", "groups": { - "label": "" + "label": "Groepen" }, "invites": { "label": "Uitnodigingen" @@ -2386,9 +2704,12 @@ "tools": { "label": "Gereedschappen", "docker": { - "label": "" + "label": "Docker" }, "logs": { + "label": "Logs" + }, + "certificates": { "label": "" } }, @@ -2401,28 +2722,28 @@ } }, "search": { - "placeholder": "", - "nothingFound": "", + "placeholder": "Zoeken naar alles", + "nothingFound": "Niets gevonden", "error": { - "fetch": "" + "fetch": "Er is een fout opgetreden tijdens het ophalen van gegevens" }, "mode": { "appIntegrationBoard": { - "help": "", + "help": "Zoeken naar apps, integraties of borden", "group": { "app": { - "title": "", + "title": "Apps", "children": { "action": { "open": { - "label": "" + "label": "Open app URL" }, "edit": { - "label": "" + "label": "App bewerken" } }, "detail": { - "title": "" + "title": "Selecteer een actie voor de app" } } }, @@ -2431,114 +2752,122 @@ "children": { "action": { "open": { - "label": "" + "label": "Bord openen" }, "homeBoard": { + "label": "Instellen als home-bord" + }, + "mobileBoard": { "label": "" }, "settings": { - "label": "" + "label": "Instellingen openen" } }, "detail": { - "title": "" + "title": "Selecteer een actie voor het bord" } } }, "integration": { - "title": "" + "title": "Integraties" } } }, "command": { - "help": "", + "help": "Commandomodus activeren", "group": { "localCommand": { - "title": "" + "title": "Lokale commando’s" }, "globalCommand": { - "title": "", + "title": "Globale commando's", "option": { "colorScheme": { - "light": "", - "dark": "" + "light": "Schakel naar lichte modus", + "dark": "Schakel naar donkere modus" }, "language": { - "label": "", + "label": "Taal wijzigen", "children": { "detail": { - "title": "" + "title": "Selecteer je voorkeurstaal" } } }, "newBoard": { - "label": "" + "label": "Een nieuw bord aanmaken" }, "importBoard": { - "label": "" + "label": "Een bord importeren" }, "newApp": { - "label": "" + "label": "Een nieuwe app aanmaken" }, "newIntegration": { - "label": "", + "label": "Een nieuwe integratie aanmaken", "children": { "detail": { - "title": "" + "title": "Selecteer het integratietype dat je wilt aanmaken" } } }, "newUser": { - "label": "" + "label": "Een nieuwe gebruiker aanmaken" }, "newInvite": { - "label": "" + "label": "Een nieuwe uitnodiging aanmaken" }, "newGroup": { - "label": "" + "label": "Een nieuwe groep aanmaken" } } } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { - "help": "", + "help": "Gebruik een externe zoekmachine", "group": { "searchEngine": { - "title": "", + "title": "Zoekmachines", "children": { "action": { "search": { - "label": "" + "label": "Zoeken met {name}" } }, "detail": { - "title": "" + "title": "Selecteer een actie voor de zoekmachine" }, "searchResults": { - "title": "" + "title": "Selecteer een zoekresultaat voor acties" } }, "option": { "google": { - "name": "", - "description": "" + "name": "Google", + "description": "Zoeken op het web met Google" }, "bing": { - "name": "", - "description": "" + "name": "Bing", + "description": "Zoeken op het web met Bing" }, "duckduckgo": { - "name": "", - "description": "" + "name": "DuckDuckGo", + "description": "Zoeken op het web met DuckDuckGo" }, "torrent": { - "name": "", - "description": "" + "name": "Verouderde torrents weergeven", + "description": "Zoeken naar torrents op torrentdownloads.pro" }, "youTube": { - "name": "", - "description": "" + "name": "YouTube", + "description": "Zoeken naar video's op YouTube" } } } @@ -2547,19 +2876,19 @@ "help": { "group": { "mode": { - "title": "" + "title": "Modi" }, "help": { - "title": "", + "title": "Help", "option": { "documentation": { "label": "Documentatie" }, "submitIssue": { - "label": "" + "label": "Een probleem melden" }, "discord": { - "label": "" + "label": "Community Discord" } } } @@ -2567,64 +2896,82 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { - "title": "" + "title": "Lokale resultaten" } } }, "page": { - "help": "", + "help": "Zoeken naar pagina’s", "group": { "page": { - "title": "", + "title": "Pagina’s", "option": { "manageHome": { - "label": "" + "label": "Startpagina beheren" }, "manageBoard": { - "label": "" + "label": "Borden beheren" }, "manageApp": { - "label": "" + "label": "Apps beheren" }, "manageIntegration": { - "label": "" + "label": "Integraties beheren" }, "manageSearchEngine": { - "label": "" + "label": "Zoekmachines beheren" }, "manageMedia": { - "label": "" + "label": "Media beheren" }, "manageUser": { "label": "Gebruikers beheren" }, "manageInvite": { - "label": "" + "label": "Uitnodigingen beheren" }, "manageGroup": { - "label": "" + "label": "Groepen beheren" }, "manageDocker": { - "label": "" + "label": "Docker beheren" }, "manageApi": { - "label": "" + "label": "Swagger API" }, "manageLog": { - "label": "" + "label": "Logs bekijken" }, "manageTask": { - "label": "" + "label": "Taken beheren" }, "manageSettings": { - "label": "" + "label": "Globale instellingen" }, "about": { "label": "Over" }, "homeBoard": { - "label": "" + "label": "Home-bord" }, "preferences": { "label": "Jouw voorkeuren" @@ -2634,37 +2981,37 @@ } }, "userGroup": { - "help": "", + "help": "Zoeken naar gebruikers of groepen", "group": { "user": { "title": "Gebruikers", "children": { "action": { "detail": { - "label": "" + "label": "Gebruikersgegevens weergeven" } }, "detail": { - "title": "" + "title": "Selecteer een actie voor de gebruiker" } } }, "group": { - "title": "", + "title": "Groepen", "children": { "action": { "detail": { - "label": "" + "label": "Groepdetails weergeven" }, "manageMember": { - "label": "" + "label": "Leden beheren" }, "managePermission": { - "label": "" + "label": "Machtigingen beheren" } }, "detail": { - "title": "" + "title": "Selecteer een actie voor de groep" } } } @@ -2672,75 +3019,132 @@ } }, "engine": { - "search": "", + "search": "Vind een zoekmachine", "field": { "name": { "label": "Naam" }, "short": { - "label": "" + "label": "Kort" }, "urlTemplate": { - "label": "" + "label": "URL zoektemplate" }, "description": { - "label": "" + "label": "Beschrijving" } }, "page": { "list": { - "title": "", + "title": "Zoekmachines", "noResults": { - "title": "", - "action": "" + "title": "Er zijn nog geen zoekmachines", + "action": "Je eerste zoekmachine aanmaken" }, - "interactive": "" + "interactive": "Interactief, gebruikt een integratie" }, "create": { - "title": "", + "title": "Nieuwe zoekmachine", "notification": { "success": { - "title": "", - "message": "" + "title": "Zoekmachine aangemaakt", + "message": "De zoekmachine is succesvol aangemaakt" }, "error": { - "title": "", - "message": "" + "title": "Zoekmachine niet aangemaakt", + "message": "De zoekmachine kon niet worden aangemaakt" } } }, "edit": { - "title": "", + "title": "Zoekmachine bewerken", "notification": { "success": { - "title": "", - "message": "" + "title": "Wijzigingen succesvol toegepast", + "message": "De zoekmachine is succesvol opgeslagen" }, "error": { - "title": "", - "message": "" + "title": "Kan wijzigingen niet toepassen", + "message": "De zoekmachine kon niet worden opgeslagen" } }, - "configControl": "", + "configControl": "Instellingen", "searchEngineType": { - "generic": "", - "fromIntegration": "" + "generic": "Algemeen", + "fromIntegration": "Van integratie" } }, "delete": { - "title": "", - "message": "", + "title": "Zoekmachine verwijderen", + "message": "Weet je zeker dat je de zoekmachine '{name}' wilt verwijderen?", "notification": { "success": { - "title": "", - "message": "" + "title": "Zoekmachine verwijderd", + "message": "De zoekmachine is succesvol verwijderd" }, "error": { - "title": "", - "message": "" + "title": "Zoekmachine niet verwijderd", + "message": "De zoekmachine kon niet worden verwijderd" } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/no.json b/packages/translation/src/lang/no.json index 7ca020a0b..07e5013e7 100644 --- a/packages/translation/src/lang/no.json +++ b/packages/translation/src/lang/no.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "Apper", + "boards": "Tavler", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "Innstillinger", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "Brukere", "name": "Bruker", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "Apper", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "Apper", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "Tidligere", "next": "Neste", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Prøv igjen", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Logg Inn", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Faresonen", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -908,13 +1043,13 @@ "label": "" }, "layout": { - "label": "", + "label": "Oppsett", "option": { "row": { - "label": "" + "label": "Horisontal" }, "column": { - "label": "" + "label": "Vertikal" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Blokkert i dag", "dnsQueriesToday": "Spørringer i dag", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Notisbok", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Nettleseren din støtter ikke iframes. Vennligst oppdater nettleseren din." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "", + "queue": "Kø", + "statistics": "" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "", + "status": { + "healthy": "", + "unhealthy": "" + } + }, + "panel": { + "statistics": { + "empty": "Tøm", + "transcodes": "", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "" + }, + "workers": { + "empty": "Tøm", + "table": { + "file": "", + "eta": "Gjenstående tid (estimat)", + "progress": "Fremgang", + "transcode": "", + "healthCheck": "" + } + }, + "queue": { + "empty": "Tøm", + "table": { + "file": "", + "size": "Størrelse", + "transcode": "", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Liten", "md": "", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Slett permanent", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Generelt", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Første dag i uken", "accessibility": "Hjelpemidler" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Generelt", - "owner": "", + "owner": "Eier", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Tavler", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Utseende", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Feil" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/pl.json b/packages/translation/src/lang/pl.json index c0dd2195c..66135f338 100644 --- a/packages/translation/src/lang/pl.json +++ b/packages/translation/src/lang/pl.json @@ -1,26 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "Witaj w Homarrze", + "subtitle": "Zacznijmy od konfiguracji twojego Homarra.", + "description": "Aby rozpocząć, wybierz jak chcesz skonfigurować Homarra.", + "action": { + "scratch": "Zacznij od zera", + "importOldmarr": "Importuj z Homarr przed 1.0" + } + }, + "import": { + "title": "Importuj dane", + "subtitle": "Możesz zaimportować dane z istniejącej instancji Homarra.", + "dropzone": { + "title": "Przeciągnij tutaj plik zip lub kliknij, aby przeglądać", + "description": "Przesłany zip zostanie przetworzony i będziesz mógł wybrać co chcesz zaimportować" + }, + "fileInfo": { + "action": { + "change": "Zmień plik" + } + }, + "importSettings": { + "title": "Importuj ustawienia", + "description": "Skonfiguruj zachowanie importu" + }, + "boardSelection": { + "title": "Znaleziono {count} tablic", + "description": "Wybierz wszystkie działy o rozmiarze do zaimportowania", + "action": { + "selectAll": "Zaznacz wszystkie", + "unselectAll": "Odznacz wszystkie" + } + }, + "summary": { + "title": "Podsumowanie importu", + "description": "W poniższym podsumowaniu możesz zobaczyć, co zostanie zaimportowane", + "action": { + "import": "Potwierdź import i kontynuuj" + }, + "entities": { + "apps": "Aplikacje", + "boards": "Tablice", + "integrations": "Integracje", + "credentialUsers": "Dane użytkowników" + } + }, + "tokenModal": { + "title": "Wpisz token importu", + "field": { + "token": { + "label": "Token", + "description": "Wprowadź token importu z poprzedniej instancji hommara" + } + }, + "notification": { + "error": { + "title": "Nieprawidłowy token", + "message": "Wprowadzony token jest nieprawidłowy" + } + } + } + }, + "user": { + "title": "Administrator", + "subtitle": "Określ dane uwierzytelniające dla administratora", + "notification": { + "success": { + "title": "Użytkownik został utworzony", + "message": "Użytkownik został pomyślnie utworzony" + }, + "error": { + "title": "Błąd podczas tworzenia użytkownika" + } + } + }, + "group": { + "title": "Zewnętrzna grupa", + "subtitle": "Określ grupę, która powinna być używana przez użytkowników zewnętrznych.", + "form": { + "name": { + "label": "Nazwa grupy", + "description": "Nazwa musi być zgodna z grupą administratora zewnętrznego dostawcy" + } + } + }, + "settings": { + "title": "Ustawienia", + "subtitle": "Konfiguruj ustawienia serwera" + }, + "finish": { + "title": "Zakończ konfigurację", + "subtitle": "Gotowe!", + "description": "Pomyślnie zakończyłeś proces konfiguracji. Teraz możesz zacząć używać Homarr. Wybierz następną akcję:", + "action": { + "goToBoard": "Idź do tablicy {name}", + "createBoard": "Stwórz swoją pierwszą tablicę", + "inviteUser": "Zaproś innych użytkowników", + "docs": "Przeczytaj dokumentację!" + } + } + }, + "backToStart": "Powrót do początku" + }, "user": { "title": "Użytkownicy", "name": "Użytkownik", "page": { "login": { - "title": "", - "subtitle": "" + "title": "Zaloguj się do swojego konta", + "subtitle": "Witamy ponownie! Wprowadź swoje dane logowania" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "Dołącz do Homarr", + "subtitle": "Witamy w Homarr! Utwórz swoje konto", + "description": "Zostałeś(aś) zaproszony(a) przez {username}" }, "init": { - "title": "", - "subtitle": "" + "title": "Nowa instalacja Homarra", + "subtitle": "Proszę utworzyć użytkownika dla podstawowego administratora" } }, "field": { "email": { "label": "E-mail", - "verified": "" + "verified": "Zweryfikowany" }, "username": { "label": "Nazwa użytkownika" @@ -28,46 +133,46 @@ "password": { "label": "Hasło", "requirement": { - "length": "", + "length": "Zawiera co najmniej 8 znaków", "lowercase": "Zawiera małą literę", "uppercase": "Zawiera wielką literę", "number": "Zawiera cyfrę", - "special": "" + "special": "Zawiera specjalny symbol" } }, "passwordConfirm": { "label": "Potwierdź hasło" }, "previousPassword": { - "label": "" + "label": "Stare hasło:" }, "homeBoard": { - "label": "" + "label": "Tablica główna" }, "pingIconsEnabled": { - "label": "" + "label": "Użyj ikon dla pingów" } }, "error": { - "usernameTaken": "" + "usernameTaken": "Nazwa użytkownika jest już zajęta" }, "action": { "login": { "label": "Zaloguj się", - "labelWith": "", + "labelWith": "Zaloguj się przez {provider}", "notification": { "success": { - "title": "", - "message": "" + "title": "Logowanie zakończone pomyślnie", + "message": "Jesteś teraz zalogowany!" }, "error": { - "title": "", - "message": "" + "title": "Logowanie nieudane", + "message": "Twoje logowanie nie powiodło się" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "Zapomniałeś(aś) hasła?", + "description": "Administrator może użyć następującej komendy do zresetowania hasła:" } }, "register": { @@ -75,81 +180,91 @@ "notification": { "success": { "title": "Utworzono konto", - "message": "" + "message": "Zaloguj się, aby kontynuować" }, "error": { - "title": "", - "message": "" + "title": "Tworzenie konta nie powiodło się", + "message": "Twoje konto nie może zostać utworzone" } } }, "create": "Dodaj użytkownika", "changePassword": { - "label": "", + "label": "Zmień hasło", "notification": { "success": { - "message": "" + "message": "Hasło zostało pomyślnie zmienione" }, "error": { - "message": "" + "message": "Problem ze zmianą hasła" } } }, "changeHomeBoard": { "notification": { "success": { - "message": "" + "message": "Tablica główna zmieniona pomyślnie" }, "error": { - "message": "" + "message": "Nie można zmienić tablicy głównej" + } + } + }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "Domyślna wyszukiwarka zmieniona pomyślnie" + }, + "error": { + "message": "Nie można zmienić domyślnej wyszukiwarki" } } }, "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "Pierwszy dzień tygodnia został pomyślnie zmieniony" }, "error": { - "message": "" + "message": "Nie można zmienić pierwszego dnia tygodnia" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "Włączono ping na ikonach" }, "error": { - "message": "" + "message": "Nie można włączyć pingowania ikon" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Zmień obraz", "notification": { "success": { - "message": "" + "message": "Obraz zmieniony pomyślnie" }, "error": { - "message": "" + "message": "Nie można zmienić obrazu" }, "toLarge": { - "title": "", - "message": "" + "title": "Obraz jest zbyt duży", + "message": "Maksymalny rozmiar obrazu to {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Usuń obraz", + "confirm": "Czy na pewno chcesz usunąć ten obraz?", "notification": { "success": { - "message": "" + "message": "Obraz został pomyślnie usunięty." }, "error": { - "message": "" + "message": "Nie można usunąć obrazu" } } } @@ -157,63 +272,63 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "Pomyślnie zaktualizowano profil" }, "error": { - "message": "" + "message": "Problem z aktualizacją profilu" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "Usuń trwale użytkownika", + "description": "Usuwa tego użytkownika, w tym jego preferencje. To nie usunie żadnych tablic. Użytkownik nie będzie powiadamiany.", + "confirm": "Czy na pewno chcesz usunąć użytkownika {username} z jego preferencjami?" }, "select": { - "label": "", - "notFound": "" + "label": "Wybierz użytkownika", + "notFound": "Nie znaleziono użytkownika" }, "transfer": { - "label": "" + "label": "Wybierz nowego właściciela" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "Grupy", + "name": "Grupa", + "search": "Znajdź grupę", "field": { "name": "Nazwa", - "members": "" + "members": "Członkowie" }, "permission": { "admin": { - "title": "", + "title": "Admin", "item": { "admin": { - "label": "", - "description": "" + "label": "Administrator", + "description": "Członkowie z tym uprawnieniem mają pełny dostęp do wszystkich funkcji i ustawień" } } }, "app": { - "title": "", + "title": "Aplikacje", "item": { "create": { - "label": "", - "description": "" + "label": "Utwórz aplikacje", + "description": "Zezwól użytkownikom na tworzenie aplikacji" }, "use-all": { - "label": "", - "description": "" + "label": "Używaj wszystkich aplikacji", + "description": "Zezwalaj użytkownikom na dodawanie aplikacji do ich tablic" }, "modify-all": { - "label": "", - "description": "" + "label": "Modyfikuj wszystkie aplikacje", + "description": "Zezwalaj użytkownikom na modyfikowanie wszystkich aplikacji" }, "full-all": { - "label": "", - "description": "" + "label": "Pełny dostęp do aplikacji", + "description": "Zezwalaj użytkownikom na zarządzanie, używanie i usuwanie dowolnej aplikacji" } } }, @@ -221,214 +336,215 @@ "title": "Tablice", "item": { "create": { - "label": "", - "description": "" + "label": "Utwórz tablice", + "description": "Zezwalaj użytkownikom na tworzenie tablic" }, "view-all": { - "label": "", - "description": "" + "label": "Wyświetl wszystkie tablice", + "description": "Zezwalaj użytkownikom na wyświetlanie wszystkich tablic" }, "modify-all": { - "label": "", - "description": "" + "label": "Modyfikuj wszystkie tablice", + "description": "Zezwalaj użytkownikom na modyfikowanie wszystkich tablic (nie uwzględnia kontroli dostępu i strefy niebezpiecznej)" }, "full-all": { - "label": "", - "description": "" + "label": "Pełny dostęp do tablicy", + "description": "Zezwalaj użytkownikom na przeglądanie, modyfikowanie i usuwanie wszystkich tablic (w tym kontroli dostępu i strefy niebezpiecznej)" } } }, "integration": { - "title": "", + "title": "Integracje", "item": { "create": { - "label": "", - "description": "" + "label": "Utwórz integracje", + "description": "Zezwalaj użytkownikom na tworzenie integracji" }, "use-all": { - "label": "", - "description": "" + "label": "Używaj wszystkich integracji", + "description": "Pozwala członkom na dodawanie integracji do ich tablic" }, "interact-all": { - "label": "", - "description": "" + "label": "Interakcja z dowolną integracją", + "description": "Zezwalaj użytkownikom na interakcję z dowolną integracją" }, "full-all": { - "label": "", - "description": "" + "label": "Pełny dostęp do integracji", + "description": "Zezwalaj użytkownikom na zarządzanie, używanie i interakcję z dowolną integracją" } } }, "media": { - "title": "", + "title": "Media", "item": { "upload": { - "label": "", - "description": "" + "label": "Prześlij media", + "description": "Zezwalaj użytkownikom na przesyłanie mediów" }, "view-all": { - "label": "", - "description": "" + "label": "Wyświetl wszystkie media", + "description": "Zezwalaj użytkownikom na wyświetlanie wszystkich mediów" }, "full-all": { - "label": "", - "description": "" + "label": "Pełny dostęp do mediów", + "description": "Zezwalaj użytkownikom na zarządzanie i usuwanie wszelkich mediów" } } }, "other": { - "title": "", + "title": "Inne", "item": { "view-logs": { - "label": "", - "description": "" + "label": "Wyświetl logi", + "description": "Zezwalaj użytkownikom na przeglądanie logów" } } }, "search-engine": { - "title": "", + "title": "Wyszukiwarki", "item": { "create": { - "label": "", - "description": "" + "label": "Utwórz wyszukiwarki", + "description": "Zezwalaj użytkownikom na tworzenie wyszukiwarek" }, "modify-all": { - "label": "", - "description": "" + "label": "Modyfikuj wszystkie wyszukiwarki", + "description": "Zezwalaj użytkownikom na modyfikację wszystkich wyszukiwarek" }, "full-all": { - "label": "", - "description": "" + "label": "Pełny dostęp do wyszukiwarki", + "description": "Zezwól użytkownikom na zarządzanie i usuwanie dowolnej wyszukiwarki" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "Niektórzy członkowie pochodzą od zewnętrznych dostawców i nie mogą być tutaj zarządzani", + "external": "Wszyscy członkowie pochodzą od zewnętrznych dostawców i nie mogą być tutaj zarządzani" }, "reservedNotice": { - "message": "" + "message": "Ta grupa jest zarezerwowana dla użycia systemowego i ogranicza niektóre działania. " }, "action": { "create": { - "label": "", + "label": "Nowa grupa", "notification": { "success": { - "message": "" + "message": "Grupa została pomyślnie utworzona" }, "error": { - "message": "" + "message": "Nie udało się utworzyć grupy" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "Przenieś własność", + "description": "Przenieś właściciela tej grupy na innego użytkownika.", + "confirm": "Czy na pewno chcesz przenieść właściciela grupy {name} na {username}?", "notification": { "success": { - "message": "" + "message": "Przeniesiono pomyślnie właściciela grupy {group} do {user} " }, "error": { - "message": "" + "message": "Nie można przenieść właściciela" } } }, "addMember": { - "label": "" + "label": "Dodaj członka" }, "removeMember": { - "label": "", - "confirm": "" + "label": "Usuń użytkownika", + "confirm": "Czy na pewno chcesz usunąć {user} z tej grupy?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "Usuń grupę", + "description": "Kiedy usuniesz grupę, nie da się jej przywrócić. Proszę się upewnić czy na pewno chcesz to zrobić.", + "confirm": "Czy na pewno chcesz usunąć grupę {name}?", "notification": { "success": { - "message": "" + "message": "Usunięto grupę {name}" }, "error": { - "message": "" + "message": "Nie udało się usunąć grupy {name}" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "Uprawnienia zostały zapisane", + "message": "Uprawnienia zostały pomyślnie zapisane" }, "error": { - "title": "", - "message": "" + "title": "Nie zapisano uprawnień", + "message": "Uprawnienia nie zostały zapisane" } } }, "update": { "notification": { "success": { - "message": "" + "message": "Grupa {name} została pomyślnie zapisana" }, "error": { - "message": "" + "message": "Nie udało się zapisać grupy {name}" } } }, "select": { - "label": "", - "notFound": "" + "label": "Wybierz grupę", + "notFound": "Nie znaleziono grupy" } } }, "app": { + "search": "Znajdź aplikację", "page": { "list": { "title": "Aplikacje", "noResults": { - "title": "", - "action": "" + "title": "Nie ma jeszcze żadnych aplikacji", + "action": "Utwórz swoją pierwszą aplikację" } }, "create": { - "title": "", + "title": "Nowa aplikacja", "notification": { "success": { - "title": "", - "message": "" + "title": "Pomyślnie utworzono", + "message": "Aplikacja została pomyślnie utworzona" }, "error": { - "title": "", - "message": "" + "title": "Tworzenie nieudane", + "message": "Aplikacja nie mogła zostać utworzona" } } }, "edit": { - "title": "", + "title": "Edytuj aplikację", "notification": { "success": { - "title": "", - "message": "" + "title": "Zmiany zostały pomyślnie zastosowane", + "message": "Aplikacja została pomyślnie zapisana" }, "error": { - "title": "", - "message": "" + "title": "Nie można wprowadzić zmian", + "message": "Nie można zapisać aplikacji" } } }, "delete": { - "title": "", - "message": "", + "title": "Usuń aplikację", + "message": "Czy na pewno chcesz usunąć aplikację {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "Usunięto pomyślnie", + "message": "Aplikacja została pomyślnie usunięta" }, "error": { - "title": "", - "message": "" + "title": "Nie udało się usunąć", + "message": "Nie można usunąć aplikacji" } } } @@ -438,65 +554,65 @@ "label": "Nazwa" }, "description": { - "label": "" + "label": "Opis" }, "url": { - "label": "" + "label": "Adres URL" } }, "action": { "select": { - "label": "", - "notFound": "" + "label": "Wybierz aplikację", + "notFound": "Nie znaleziono aplikacji" } } }, "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "Integracje", + "search": "Wyszukaj integrację", "noResults": { - "title": "" + "title": "Nie ma jeszcze integracji" } }, "create": { - "title": "", + "title": "Nowa integracja {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "Utworzenie udało się", + "message": "Integracja została pomyślnie utworzona" }, "error": { - "title": "", - "message": "" + "title": "Nie udało się utworzyć", + "message": "Integracja nie może zostać utworzona" } } }, "edit": { - "title": "", + "title": "Edytuj integrację z {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "Zmiany zostały pomyślnie zastosowane", + "message": "Integracja została pomyślnie zapisana" }, "error": { - "title": "", - "message": "" + "title": "Nie można wprowadzić zmian", + "message": "Integracja nie mogła zostać zapisana" } } }, "delete": { - "title": "", - "message": "", + "title": "Usuń integrację", + "message": "Czy na pewno chcesz usunąć integrację z {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "Usunięto pomyślnie", + "message": "Integracja została pomyślnie usunięta" }, "error": { - "title": "", - "message": "" + "title": "Nie udało się usunąć", + "message": "Nie udało się usunąć integracji" } } } @@ -506,105 +622,113 @@ "label": "Nazwa" }, "url": { - "label": "" + "label": "Adres URL" + }, + "attemptSearchEngineCreation": { + "label": "Utwórz wyszukiwarkę", + "description": "Integracja \"{kind}\" może być używana z wyszukiwarkami. Zaznacz to, aby automatycznie skonfigurować wyszukiwarkę." } }, "action": { - "create": "" + "create": "Nowa integracja" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "Sprawdź połączenie i utwórz", + "edit": "Sprawdź połączenie i zapisz" }, - "alertNotice": "", + "alertNotice": "Przycisk Zapisz jest włączony po nawiązaniu pomyślnego połączenia", "notification": { "success": { - "title": "", - "message": "" + "title": "Połączenie przebiegło pomyślnie", + "message": "Połączenie zostało pomyślnie nawiązane" }, "invalidUrl": { "title": "Nieprawidłowy URL", - "message": "" + "message": "Adres URL jest nieprawidłowy" }, "secretNotDefined": { - "title": "", - "message": "" + "title": "Brakujące poświadczenia", + "message": "Nie podano wszystkich poświadczeń" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "Nieprawidłowe poświadczenia", + "message": "Poświadczenia są nieprawidłowe" }, "commonError": { - "title": "", - "message": "" + "title": "Nie udało się połączyć", + "message": "Nie udało się nawiązać połączenia" }, "badRequest": { - "title": "", - "message": "" + "title": "Błędne zapytanie", + "message": "Zapytanie zostało uszkodzone" }, "unauthorized": { - "title": "", - "message": "" + "title": "Błąd uwierzytelnienia", + "message": "Prawdopodobnie nieprawidłowe poświadczenia" }, "forbidden": { - "title": "", - "message": "" + "title": "Odmowa dostępu", + "message": "Prawdopodobnie brakuje uprawnień" }, "notFound": { - "title": "", - "message": "" + "title": "Nie znaleziono", + "message": "Prawdopodobnie błędny adres URL lub ścieżka" }, "internalServerError": { - "title": "", - "message": "" + "title": "Wewnętrzny błąd serwera", + "message": "Wystąpił błąd serwera" }, "serviceUnavailable": { - "title": "", - "message": "" + "title": "Usługa niedostępna", + "message": "Serwer jest obecnie niedostępny" }, "connectionAborted": { - "title": "", - "message": "" + "title": "Połączenie przerwano", + "message": "Połączenie zostało przerwane" }, "domainNotFound": { - "title": "", - "message": "" + "title": "Domena nie została znaleziona", + "message": "Nie można odnaleźć domeny" }, "connectionRefused": { - "title": "", - "message": "" + "title": "Połączenie odrzucone", + "message": "Połączenie zostało odrzucone" }, "invalidJson": { - "title": "", - "message": "" + "title": "Nieprawidłowy JSON", + "message": "Odpowiedź nie była prawidłowym JSON'em" }, "wrongPath": { - "title": "", - "message": "" + "title": "Błędna ścieżka", + "message": "Ścieżka jest prawdopodobnie niepoprawna" } } }, "secrets": { - "title": "", - "lastUpdated": "", - "secureNotice": "", + "title": "Sekrety", + "lastUpdated": "Data ostatniej aktualizacji: {date}", + "notSet": { + "label": "Nie ustawiono wartości", + "tooltip": "Ten wymagany sekret nie został jeszcze ustawiony" + }, + "secureNotice": "Ten sekret nie może zostać pobrany po utworzeniu", "reset": { - "title": "", - "message": "" + "title": "Resetuj sekret", + "message": "Czy na pewno chcesz zresetować ten sekret?" }, "noSecretsRequired": { - "segmentTitle": "", - "text": "" + "segmentTitle": "Brak sekretów", + "text": "Dla tej integracji nie są wymagane żadne sekrety" }, "kind": { "username": { "label": "Nazwa użytkownika", - "newLabel": "" + "newLabel": "Nowa nazwa użytkownika" }, "apiKey": { - "label": "", - "newLabel": "" + "label": "Klucz API", + "newLabel": "Nowy klucz API" }, "password": { "label": "Hasło", @@ -613,14 +737,14 @@ } }, "permission": { - "use": "", - "interact": "", - "full": "" + "use": "Wybierz integrację w elementach", + "interact": "Interakcja z integracjami", + "full": "Pełny dostęp do integracji" } }, "media": { - "plural": "", - "search": "", + "plural": "Medias", + "search": "Znajdź media", "field": { "name": "Nazwa", "size": "Rozmiar", @@ -628,119 +752,127 @@ }, "action": { "upload": { - "label": "", - "file": "", + "label": "Prześlij media", + "file": "Wybierz plik", "notification": { "success": { - "message": "" + "message": "Plik multimedialny został przesłany pomyślnie" }, "error": { - "message": "" + "message": "Nie można przesłać multimediów" } } }, "delete": { - "label": "", - "description": "", + "label": "Usuń media", + "description": "Czy na pewno chcesz usunąć media ?", "notification": { "success": { - "message": "" + "message": "Plik został usunięty pomyślnie" }, "error": { - "message": "" + "message": "Nie udało się usunąć mediów" } } }, "copy": { - "label": "" + "label": "Kopiuj adres URL" } } }, "common": { - "beta": "", + "beta": "Wersja beta", "error": "Błąd", "action": { "add": "Dodaj", "apply": "Zastosuj", - "backToOverview": "", + "backToOverview": "Powrót do widoku ogólnego", "create": "Utwórz", "edit": "Edytuj", - "import": "", + "import": "Importuj", "insert": "Wstaw", "remove": "Usuń", "save": "Zapisz", "saveChanges": "Zapisz zmiany", "cancel": "Anuluj", "delete": "Usuń", - "discard": "", + "discard": "Odrzuć", "confirm": "Potwierdź", - "continue": "", + "continue": "Kontynuuj", "previous": "Poprzedni", "next": "Dalej", - "checkoutDocs": "", + "checkoutDocs": "Sprawdź dokumentację", + "checkLogs": "Sprawdź logi, aby uzyskać więcej informacji.", "tryAgain": "Spróbuj ponownie", - "loading": "" + "loading": "Ładowanie" }, - "here": "", + "here": "tutaj", "iconPicker": { - "label": "", - "header": "" + "label": "adres URL ikony", + "header": "Wpisz nazwę lub obiekty do filtrowania ikon... Homarr przeszuka dla Ciebie ikony {countIcons}." + }, + "colorScheme": { + "options": { + "light": "Jasny", + "dark": "Ciemny" + } }, "information": { - "min": "", - "max": "", - "days": "", - "hours": "", - "minutes": "" + "min": "Min", + "max": "Max.", + "days": "Dni", + "hours": "Godziny", + "minutes": "Minuty" }, "notification": { "create": { - "success": "", - "error": "" + "success": "Utworzenie udało się", + "error": "Tworzenie nie powiodło się" }, "delete": { - "success": "", - "error": "" + "success": "Usunięto pomyślnie", + "error": "Nie udało się usunąć" }, "update": { - "success": "", - "error": "" + "success": "Zmiany zostały pomyślnie zastosowane", + "error": "Nie można wprowadzić zmian" }, "transfer": { - "success": "", - "error": "" + "success": "Pomyślnie przesłano", + "error": "Przesłanie się nie powiodło" } }, "multiSelect": { - "placeholder": "" + "placeholder": "Wybierz jedną lub więcej wartości" }, "multiText": { - "placeholder": "", - "addLabel": "" + "placeholder": "Dodaj więcej wartości", + "addLabel": "Dodaj {value}" }, "select": { - "placeholder": "", + "placeholder": "Wybierz wartość", "badge": { - "recommended": "" + "recommended": "Rekomendowane" } }, "userAvatar": { "menu": { - "switchToDarkMode": "", - "switchToLightMode": "", - "management": "", + "switchToDarkMode": "Przełącz na tryb nocny", + "switchToLightMode": "Przełącz na tryb jasny", + "management": "Zarządzanie", "preferences": "Twoje preferencje", - "logout": "", + "logout": "Wyloguj się", "login": "Zaloguj się", - "homeBoard": "", - "loggedOut": "" + "homeBoard": "Twoja tablica główna", + "loggedOut": "Wylogowano", + "updateAvailable": "Dostępne aktualizacje {countUpdates} : {tag}" } }, "dangerZone": "Strefa zagrożenia", "noResults": "Nie znaleziono żadnych wyników", "preview": { - "show": "", - "hide": "" + "show": "Pokaż podgląd", + "hide": "Ukryj podgląd" }, "zod": { "errors": { @@ -750,7 +882,7 @@ "startsWith": "To pole musi zaczynać się od {startsWith}", "endsWith": "To pole musi kończyć się na {endsWith}", "includes": "Pole to musi zawierać {includes}", - "invalidEmail": "" + "invalidEmail": "W tym polu musi znajdować się prawidłowy adres e-mail" }, "tooSmall": { "string": "To pole musi mieć co najmniej {minimum} znaków", @@ -761,12 +893,14 @@ "number": "Wartość tego pola musi być mniejsza lub równa {maximum}" }, "custom": { - "passwordsDoNotMatch": "", - "passwordRequirements": "", - "boardAlreadyExists": "", - "invalidFileType": "", - "fileTooLarge": "", - "invalidConfiguration": "" + "passwordsDoNotMatch": "Wprowadzone hasła nie zgadzają się", + "passwordRequirements": "Twoje hasło nie spełnia wymagań.", + "boardAlreadyExists": "Tablica o tej nazwie już istnieje", + "invalidFileType": "Nieprawidłowy typ pliku, oczekiwany {expected}", + "invalidFileName": "", + "fileTooLarge": "Plik jest zbyt duży, maksymalny rozmiar to {maxSize}", + "invalidConfiguration": "Nieprawidłowa konfiguracja", + "groupNameTaken": "Nazwa użytkownika jest już zajęta" } } } @@ -774,12 +908,12 @@ "section": { "dynamic": { "action": { - "create": "", - "remove": "" + "create": "Nowa sekcja dynamiczna", + "remove": "Usuń sekcję dynamiczną" }, "remove": { - "title": "", - "message": "" + "title": "Usuń sekcję dynamiczną", + "message": "Czy na pewno chcesz usunąć tę sekcję dynamiczną? Elementy zostaną przeniesione w tej samej lokalizacji w sekcji nadrzędnej." } }, "category": { @@ -789,29 +923,29 @@ } }, "action": { - "create": "", - "edit": "", - "remove": "", + "create": "Nowa kategoria", + "edit": "Zmień nazwę kategorii", + "remove": "Usuń kategorię", "moveUp": "Przenieś w górę", "moveDown": "Przenieś w dół", - "createAbove": "", - "createBelow": "" + "createAbove": "Nowa kategoria powyżej", + "createBelow": "Nowa kategoria poniżej" }, "create": { - "title": "", - "submit": "" + "title": "Nowa kategoria", + "submit": "Dodaj kategorię" }, "remove": { - "title": "", - "message": "" + "title": "Usuń kategorię", + "message": "Czy na pewno chcesz usunąć kategorię {name}?" }, "edit": { - "title": "", - "submit": "" + "title": "Zmień nazwę kategorii", + "submit": "Zmień nazwę kategorii" }, "menu": { "label": { - "create": "", + "create": "Nowa kategoria", "changePosition": "Zmiana pozycji" } } @@ -819,12 +953,12 @@ }, "item": { "action": { - "create": "", - "import": "", - "edit": "", - "moveResize": "", - "duplicate": "", - "remove": "" + "create": "Nowa pozycja", + "import": "Importuj pozycję", + "edit": "Edytuj pozycję", + "moveResize": "Przenieś / zmień rozmiar pozycji", + "duplicate": "Duplikuj pozycję", + "remove": "Usuń pozycję" }, "menu": { "label": { @@ -832,11 +966,12 @@ } }, "create": { - "title": "", - "addToBoard": "" + "title": "Wybierz element do dodania", + "search": "Filtrowanie elementów", + "addToBoard": "Dodaj do tablicy" }, "moveResize": { - "title": "", + "title": "Przenieś / zmień rozmiar pozycji", "field": { "width": { "label": "Szerokość" @@ -845,91 +980,91 @@ "label": "Wysokość" }, "xOffset": { - "label": "" + "label": "Przesunięcie X" }, "yOffset": { - "label": "" + "label": "Przesunięcie Y" } } }, "edit": { - "title": "", + "title": "Edytuj pozycje", "advancedOptions": { - "label": "", - "title": "" + "label": "Ustawienia zaawansowane", + "title": "Zaawansowane opcje pozycji" }, "field": { "integrations": { - "label": "" + "label": "Integracje" }, "customCssClasses": { - "label": "" + "label": "Niestandardowe klasy CSS" } } }, "remove": { - "title": "", - "message": "" + "title": "Usuń pozycję", + "message": "Jesteś pewien, że chcesz usunąć ten element?" } }, "widget": { "app": { - "name": "", - "description": "", + "name": "Aplikacja", + "description": "Osadza aplikację w płytce.", "option": { "appId": { - "label": "" + "label": "Wybierz aplikację" }, "openInNewTab": { "label": "Otwórz w nowej karcie" }, "showTitle": { - "label": "" + "label": "Pokaż nazwę aplikacji" }, "showDescriptionTooltip": { - "label": "" + "label": "Pokaż opis podpowiedzi" }, "pingEnabled": { - "label": "" + "label": "Włącz prosty ping" } }, "error": { "notFound": { - "label": "", - "tooltip": "" + "label": "Brak aplikacji", + "tooltip": "Nie wybrano prawidłowej aplikacji" } } }, "bookmarks": { - "name": "", - "description": "", + "name": "Zakładki", + "description": "Wyświetla wiele linków do aplikacji", "option": { "title": { - "label": "" + "label": "Tytuł" }, "layout": { - "label": "", + "label": "Układ", "option": { "row": { - "label": "" + "label": "Poziomy" }, "column": { - "label": "" + "label": "Pionowy" }, "grid": { - "label": "" + "label": "Siatka" } } }, "items": { - "label": "", - "add": "" + "label": "Zakładki", + "add": "Dodaj zakładkę" } } }, "dnsHoleSummary": { - "name": "", - "description": "", + "name": "Podsumowanie Hole DNS", + "description": "Wyświetla podsumowanie Twojego hosta DNS", "option": { "layout": { "label": "Układ", @@ -941,27 +1076,28 @@ "label": "Pionowy" }, "grid": { - "label": "" + "label": "Siatka" } } }, "usePiHoleColors": { - "label": "" + "label": "Użyj kolorów Pi-Hole" } }, "error": { - "internalServerError": "", - "integrationsDisconnected": "" + "internalServerError": "Nie udało się pobrać podsumowanie Hole DNS", + "integrationsDisconnected": "Brak dostępnych danych, wszystkie integracje odłączone" }, "data": { "adsBlockedToday": "Zablokowane dzisiaj", "adsBlockedTodayPercentage": "Zablokowane dzisiaj", "dnsQueriesToday": "Zapytania dzisiaj", - "domainsBeingBlocked": "" - } + "domainsBeingBlocked": "Domeny na liście blokowanych" + }, + "domainsTooltip": "Ze względu na wiele integracji, Homarr nie może obliczyć dokładnej liczby zablokowanych domen" }, "dnsHoleControls": { - "name": "", + "name": "Sterowanie dziurami DNS", "description": "Kontroluj PiHole lub AdGuard ze swojego pulpitu", "option": { "layout": { @@ -974,68 +1110,87 @@ "label": "Pionowy" }, "grid": { - "label": "" + "label": "Siatka" } } }, "showToggleAllButtons": { - "label": "" + "label": "Pokaż \"pokaż wszystkie przyciski\" przycisk" } }, "error": { - "internalServerError": "" + "internalServerError": "Nie udało się kontrolować funkcji DNS Hole" }, "controls": { - "enableAll": "", - "disableAll": "", - "setTimer": "", - "set": "", + "enableAll": "Włącz wszystkie", + "disableAll": "Wyłącz wszystkie", + "setTimer": "Ustaw wyłącznik czasowy", + "set": "Ustaw", "enabled": "Włączony", "disabled": "Wyłączony", - "processing": "", - "disconnected": "", - "hours": "", - "minutes": "", - "unlimited": "" + "processing": "Przetwarzanie", + "disconnected": "Rozłączono", + "hours": "Godziny", + "minutes": "Minuty", + "unlimited": "Pozostaw puste do nieograniczonej" } }, "clock": { - "name": "", + "name": "Data i czas", "description": "Wyświetla bieżącą datę i godzinę.", "option": { "customTitleToggle": { - "label": "", - "description": "" + "label": "Niestandardowe wyświetlanie tytułu/miasta", + "description": "Pokaż własny tytuł lub nazwę miasta/kraju na górze zegara." }, "customTitle": { - "label": "" + "label": "Tytuł" }, "is24HourFormat": { - "label": "", - "description": "" + "label": "Format 24-godzinny", + "description": "Użyj 24-godzinnego formatu zamiast 12-godzinnego" }, "showSeconds": { - "label": "" + "label": "Wyświetlaj sekundy" }, "useCustomTimezone": { - "label": "" + "label": "Użyj stałej strefy czasowej" }, "timezone": { "label": "Strefa czasowa", - "description": "" + "description": "Wybierz strefę czasową zgodnie ze standardem IANA" }, "showDate": { - "label": "" + "label": "Pokaż datę" }, "dateFormat": { - "label": "", - "description": "" + "label": "Format daty", + "description": "Jak powinna wyglądać data" } } }, + "minecraftServerStatus": { + "name": "Status serwera Minecraft", + "description": "Wyświetla status serwera Minecraft", + "option": { + "title": { + "label": "Tytuł" + }, + "domain": { + "label": "Adres serwera" + }, + "isBedrockServer": { + "label": "Serwer Bedrock" + } + }, + "status": { + "online": "Dostępny", + "offline": "Niedostępny" + } + }, "notebook": { "name": "Notatnik", - "description": "", + "description": "Prosty widżet notatnika obsługujący markdown", "option": { "showToolbar": { "label": "Pokaż pasek narzędzi ułatwiający pisanie w markdown" @@ -1095,7 +1250,7 @@ } }, "iframe": { - "name": "", + "name": "iFrame", "description": "Osadzaj dowolne treści z internetu. Niektóre strony internetowe mogą ograniczać dostęp.", "option": { "embedUrl": { @@ -1127,31 +1282,32 @@ } }, "error": { - "noUrl": "", + "noUrl": "Adres URL iFrame nie został podany", + "unsupportedProtocol": "Podany adres URL używa nieobsługiwanego protokołu. Proszę użyć jednego z ({supportedProtocols})", "noBrowerSupport": "Twoja przeglądarka nie obsługuje ramek iframe. Zaktualizuj przeglądarkę." } }, "smartHome-entityState": { - "name": "", - "description": "", + "name": "Stan obiektu", + "description": "Wyświetl stan obiektu i przełącz go opcjonalnie", "option": { "entityId": { - "label": "ID encji" + "label": "ID obiektu" }, "displayName": { - "label": "" + "label": "Wyświetlana nazwa" }, "entityUnit": { - "label": "" + "label": "Jednostka" }, "clickable": { - "label": "" + "label": "Element klikalny" } } }, "smartHome-executeAutomation": { - "name": "", - "description": "", + "name": "Wykonaj automatyzację", + "description": "Uruchom automatyzację jednym kliknięciem", "option": { "displayName": { "label": "Nazwa wyświetlana" @@ -1161,26 +1317,26 @@ } }, "spotlightAction": { - "run": "" + "run": "Uruchom {name}" } }, "calendar": { "name": "Kalendarz", - "description": "", + "description": "Wyświetlaj zdarzenia z integracji w widoku kalendarza w określonym okresie czasowym", "option": { "releaseType": { "label": "Rodzaj premiery w Radarr", "options": { - "inCinemas": "", - "digitalRelease": "", - "physicalRelease": "" + "inCinemas": "W kinach", + "digitalRelease": "Wydanie cyfrowe", + "physicalRelease": "Wydanie fizyczne" } }, "filterPastMonths": { - "label": "" + "label": "Początek od" }, "filterFutureMonths": { - "label": "" + "label": "Koniec o" } } }, @@ -1189,24 +1345,24 @@ "description": "Wyświetla aktualne informacje o pogodzie w ustawionej lokalizacji.", "option": { "isFormatFahrenheit": { - "label": "" + "label": "Temperatura w Fahrenheit" }, "location": { "label": "Lokalizacja pogody" }, "showCity": { - "label": "" + "label": "Pokaż miasto" }, "hasForecast": { - "label": "" + "label": "Pokaż Prognozę" }, "forecastDayCount": { - "label": "", - "description": "" + "label": "Liczba dni prognozy", + "description": "Kiedy widżet nie jest wystarczająco szeroki, mniej dni jest wyświetlane" }, "dateFormat": { - "label": "", - "description": "" + "label": "Format daty", + "description": "Jak powinna wyglądać data" } }, "kind": { @@ -1227,72 +1383,72 @@ } }, "indexerManager": { - "name": "", - "description": "", + "name": "Status menedżera indeksu", + "description": "Status Twoich indeksów", "option": { "openIndexerSiteInNewTab": { - "label": "" + "label": "Otwórz stronę indeksującą w nowej karcie" } }, - "title": "", - "testAll": "", + "title": "Menedżer indeksów", + "testAll": "Przetestuj wszystkie", "error": { - "internalServerError": "" + "internalServerError": "Nie udało się pobrać statusu indeksów" } }, "healthMonitoring": { - "name": "", - "description": "", + "name": "Monitorowanie zdrowia systemu", + "description": "Wyświetla informacje o stanie Twojego systemu(ów).", "option": { "fahrenheit": { - "label": "" + "label": "Temperatura procesora w Fahrenheit" }, "cpu": { - "label": "" + "label": "Pokaż informacje o procesorze" }, "memory": { - "label": "" + "label": "Pokaż informacje o pamięci" }, "fileSystem": { - "label": "" + "label": "Pokaż informacje o systemie plików" } }, "popover": { - "information": "", - "processor": "", - "memory": "", - "memoryAvailable": "", - "version": "", + "information": "Informacja", + "processor": "Procesor: {cpuModelName}", + "memory": "Pamięć: {memory}GiB", + "memoryAvailable": "Dostępna pamięć {memoryAvailable} GB ({percent}%)", + "version": "Wersja: {version}", "uptime": "", - "loadAverage": "", - "minute": "", - "minutes": "", - "used": "", - "available": "", - "lastSeen": "" + "loadAverage": "Średnie obciążenie", + "minute": "1 minuta", + "minutes": "{count} minut", + "used": "Używane", + "available": "Dostępne", + "lastSeen": "Ostatnia aktualizacja statusu: {lastSeen}" }, "memory": {}, "error": { - "internalServerError": "" + "internalServerError": "Nie udało się pobrać stanu zdrowia" } }, "common": { "location": { - "query": "", - "latitude": "", - "longitude": "", - "disabledTooltip": "", - "unknownLocation": "", + "query": "Miasto / kod pocztowy", + "latitude": "Szerokość geograficzna (Latitude)", + "longitude": "Długość geograficzna (Longitude)", + "disabledTooltip": "Podaj miasto lub kod pocztowy.", + "unknownLocation": "Nieznana lokalizacja", "search": "Szukaj", "table": { "header": { - "city": "", - "country": "", - "coordinates": "", - "population": "" + "city": "Miasto", + "country": "Kraj", + "coordinates": "Współrzędne", + "population": "Populacja" }, "action": { - "select": "" + "select": "Wybierz {city}, {countryCode}" }, "population": { "fallback": "Nieznany" @@ -1300,19 +1456,16 @@ } }, "integration": { - "noData": "", - "description": "" + "noData": "Nie znaleziono integracji", + "description": "Kliknij aby utworzyć nową integrację" }, "app": { - "noData": "", - "description": "" + "noData": "Nie znaleziono aplikacji", + "description": "Kliknij aby utworzyć nową aplikację" }, "error": { - "action": { - "logs": "" - }, - "noIntegration": "", - "noData": "" + "noIntegration": "Nie wybrano integracji", + "noData": "Brak danych dotyczących integracji" }, "option": {} }, @@ -1325,167 +1478,172 @@ }, "hasAutoPlay": { "label": "Autoodtwarzanie", - "description": "" + "description": "Automatyczne odtwarzanie działa tylko po wyciszeniu odtwarzacza z powodu ograniczeń przeglądarki" }, "isMuted": { - "label": "" + "label": "Wyciszono" }, "hasControls": { - "label": "" + "label": "Pokaż klawisze nawigacyjne" } }, "error": { - "noUrl": "", - "forYoutubeUseIframe": "" + "noUrl": "Nie podano adresu URL wideo", + "forYoutubeUseIframe": "Dla filmów YouTube użyj opcji iframe" } }, "mediaServer": { - "name": "", - "description": "", - "option": {} + "name": "Bieżące strumienie serwera multimediów", + "description": "Pokaż bieżące strumienie na serwerach multimedialnych", + "option": {}, + "items": { + "user": "Użytkownik", + "name": "Nazwa", + "id": "ID" + } }, "downloads": { - "name": "", - "description": "", + "name": "Klient pobierania", + "description": "Pozwala na oglądanie i zarządzanie pobieraniem zarówno przez klientów Torrent, jak i Usenet.", "option": { "columns": { - "label": "" + "label": "Kolumny do pokazania" }, "enableRowSorting": { - "label": "" + "label": "Włącz sortowanie przedmiotów" }, "defaultSort": { - "label": "" + "label": "Kolumna używana do sortowania domyślnie" }, "descendingDefaultSort": { - "label": "" + "label": "Odwróć sortowanie" }, "showCompletedUsenet": { - "label": "" + "label": "Pokaż wpisy usenet oznaczone jako zakończone" }, "showCompletedTorrent": { - "label": "" + "label": "Pokaż wpisy torrent oznaczone jako ukończone" }, "activeTorrentThreshold": { - "label": "" + "label": "Ukryj ukończony torrent poniżej tego progu (w kiB/s)" }, "categoryFilter": { - "label": "" + "label": "Kategorie/etykiety do filtrowania" }, "filterIsWhitelist": { - "label": "" + "label": "Filtruj jako białą listę" }, "applyFilterToRatio": { - "label": "" + "label": "Użyj filtra do obliczenia współczynnika" } }, "errors": { - "noColumns": "", - "noCommunications": "" + "noColumns": "Wybierz kolumny w elementach", + "noCommunications": "Nie można załadować danych z integracji" }, "items": { "actions": { - "columnTitle": "" + "columnTitle": "Sterowanie" }, "added": { - "columnTitle": "", + "columnTitle": "Dodano", "detailsTitle": "Data dodania" }, "category": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Dodatki", + "detailsTitle": "Kategorie (lub dodatkowe informacje)" }, "downSpeed": { "columnTitle": "Pobieranie", "detailsTitle": "Prędkość pobierania" }, "index": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "#", + "detailsTitle": "Bieżący indeks w ramach klienta" }, "id": { - "columnTitle": "" + "columnTitle": "ID" }, "integration": { "columnTitle": "Integracja" }, "name": { - "columnTitle": "" + "columnTitle": "Nazwa zlecenia" }, "progress": { "columnTitle": "Postęp", - "detailsTitle": "" + "detailsTitle": "Postęp pobierania" }, "ratio": { "columnTitle": "Proporcja", - "detailsTitle": "" + "detailsTitle": "Współczynnik torrenta (otrzymany/wysłany)" }, "received": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Łączne pobieranie", + "detailsTitle": "Łącznie pobrano" }, "sent": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Łączne wysyłanie", + "detailsTitle": "Łącznie wysłano" }, "size": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Rozmiar pliku", + "detailsTitle": "Całkowity rozmiar zaznaczenia/plików" }, "state": { "columnTitle": "Status", - "detailsTitle": "" + "detailsTitle": "Stan pracy" }, "time": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Czas zakończenia", + "detailsTitle": "Czas od/do zakończenia" }, "type": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Typ", + "detailsTitle": "Pobierz typ klienta" }, "upSpeed": { "columnTitle": "Udostępnianie", - "detailsTitle": "" + "detailsTitle": "Prędkość wysyłania" } }, "states": { "downloading": "Pobieranie", - "queued": "", + "queued": "W kolejce", "paused": "Zatrzymane", "completed": "Zakończono", - "failed": "", - "processing": "", - "leeching": "", - "stalled": "", + "failed": "Nieudane", + "processing": "Przetwarzanie", + "leeching": "Leeching", + "stalled": "Zatrzymano", "unknown": "Nieznany", - "seeding": "" + "seeding": "Wysyłanie" }, "actions": { "clients": { - "modalTitle": "", + "modalTitle": "Pobierz listę klientów", "pause": "", "resume": "" }, "client": { - "pause": "", - "resume": "" + "pause": "Wstrzymaj klienta", + "resume": "Wznów klient" }, "item": { - "pause": "", - "resume": "", + "pause": "Wstrzymaj element", + "resume": "Wznów element", "delete": { - "title": "", - "modalTitle": "", - "entry": "", - "entryAndFiles": "" + "title": "Usuń przedmiot", + "modalTitle": "Czy jesteś pewien, że chcesz skasować to zadanie?", + "entry": "Usuń wpis", + "entryAndFiles": "Usuń wpis i plik(i)" } } }, - "globalRatio": "" + "globalRatio": "Wskaźnik globalny" }, "mediaRequests-requestList": { - "name": "", + "name": "Lista żądań multimediów", "description": "Zobacz listę wszystkich zapytań o media z Twoich instancji Overseerr lub Jellyseerr", "option": { "linksTargetNewTab": { @@ -1493,21 +1651,21 @@ } }, "pending": { - "approve": "", - "approving": "", - "decline": "" + "approve": "Zatwierdź prośbę", + "approving": "Zatwierdzanie zapytania...", + "decline": "Odrzuć prośbę" }, "availability": { "unknown": "Nieznany", - "pending": "", - "processing": "", + "pending": "Oczekujący", + "processing": "Przetwarzanie", "partiallyAvailable": "", - "available": "" + "available": "Dostępne" }, "toBeDetermined": "" }, "mediaRequests-requestStats": { - "name": "", + "name": "Statystyki zapytań o media", "description": "Statystyki Twoich zapytań o media", "option": {}, "titles": { @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "Domyślny widok" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "", + "queue": "Kolejka", + "statistics": "" + }, + "currentIndex": "{start}-{end} z {total}", + "healthCheck": { + "title": "Ocena stanu zdrowia", + "queued": "W kolejce", + "status": { + "healthy": "", + "unhealthy": "" + } + }, + "panel": { + "statistics": { + "empty": "Puste", + "transcodes": "", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "Pliki: {value}", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "" + }, + "workers": { + "empty": "Puste", + "table": { + "file": "", + "eta": "", + "progress": "Postęp", + "transcode": "", + "healthCheck": "" + } + }, + "queue": { + "empty": "Puste", + "table": { + "file": "", + "size": "Rozmiar", + "transcode": "", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1598,7 +1829,7 @@ "description": "" }, "onlyImportApps": { - "label": "", + "label": "Import tylko aplikacje", "description": "" } }, @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Mały", "md": "Średni", @@ -1725,7 +1957,7 @@ "metaTitle": "" }, "setting": { - "title": "", + "title": "Ustawienia tablicy {boardName}", "section": { "general": { "title": "Ogólne", @@ -1783,7 +2015,7 @@ "confirm": { "public": { "title": "", - "description": "" + "description": "Czy na pewno chcesz sprawić, by ta tablica była prywatna? Tablica nie będzie publiczna. Linki dla gości nie będą działać." }, "private": { "title": "", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Usuń trwale", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Ogólne", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Pierwszy dzień tygodnia", "accessibility": "Ułatwienia dostępu" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Ogólne", - "owner": "", + "owner": "Właściciel", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Tablice", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Wygląd", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Błąd" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/pt.json b/packages/translation/src/lang/pt.json index 3a5ed4932..dbbc5e9fa 100644 --- a/packages/translation/src/lang/pt.json +++ b/packages/translation/src/lang/pt.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "Aplicativos", + "boards": "Placas", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "Configurações", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "Usuários", "name": "Usuário", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "Aplicativos", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "Aplicativos", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "Anterior", "next": "Próximo", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Tente novamente", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "“Login”", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Zona de risco", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Bloqueado hoje", "dnsQueriesToday": "Consultas hoje", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Caderno de anotações", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Seu navegador não suporta iframes. Atualize seu navegador." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "", + "queue": "Fila", + "statistics": "Estatísticas" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "", + "status": { + "healthy": "", + "unhealthy": "" + } + }, + "panel": { + "statistics": { + "empty": "Vazio", + "transcodes": "", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "" + }, + "workers": { + "empty": "Vazio", + "table": { + "file": "Ficheiro", + "eta": "TED", + "progress": "Progresso", + "transcode": "Transcodificar", + "healthCheck": "" + } + }, + "queue": { + "empty": "Vazio", + "table": { + "file": "Ficheiro", + "size": "Tamanho", + "transcode": "Transcodificar", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Pequeno", "md": "Médio", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Excluir permanentemente", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Geral", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Primeiro dia da semana", "accessibility": "Acessibilidade" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Geral", - "owner": "", + "owner": "Dono", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Placas", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Aparência", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Erro" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/ro.json b/packages/translation/src/lang/ro.json index deadfdb40..713841aa6 100644 --- a/packages/translation/src/lang/ro.json +++ b/packages/translation/src/lang/ro.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "Aplicații", + "boards": "Planșe", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "Setări", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "Utilizatori", "name": "Utilizator", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "Aplicații", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "Aplicații", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "Anteriorul", "next": "Următorul", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Încearcă din nou", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Utilizator", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Zonă periculoasă", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -908,10 +1043,10 @@ "label": "" }, "layout": { - "label": "", + "label": "Aspect", "option": { "row": { - "label": "" + "label": "Orizontal" }, "column": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Blocate astăzi", "dnsQueriesToday": "Interogări astăzi", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Agendă", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Browser-ul tău nu acceptă iFrames. Te rugăm să actualizezi browser-ul." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "Afișare implicită" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "Lucrători", + "queue": "Listă de așteptare", + "statistics": "Statistici" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "Pus în așteptare", + "status": { + "healthy": "Sănătos", + "unhealthy": "Nesănătos" + } + }, + "panel": { + "statistics": { + "empty": "Gol", + "transcodes": "Transcrieri", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "Codec-uri", + "videoContainers": "Containere", + "videoResolutions": "Rezoluţie" + }, + "workers": { + "empty": "Gol", + "table": { + "file": "Fișier", + "eta": "Timp rămas estimat", + "progress": "Progres", + "transcode": "Transcriere", + "healthCheck": "" + } + }, + "queue": { + "empty": "Gol", + "table": { + "file": "Fișier", + "size": "Mărime", + "transcode": "Transcriere", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Mic", "md": "Mediu", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Șterge definitiv", "confirm": { @@ -1923,7 +2198,14 @@ "title": "", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Prima zi a săptămâni", "accessibility": "Accesibilitate" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "", - "owner": "", + "owner": "Proprietar", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Planșe", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Aspect", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Eroare" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/ru.json b/packages/translation/src/lang/ru.json index 0c42d7040..1bd029d4c 100644 --- a/packages/translation/src/lang/ru.json +++ b/packages/translation/src/lang/ru.json @@ -1,26 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "Добро пожаловать в Homarr", + "subtitle": "Давайте начнем настройку вашего экземпляра Homarr.", + "description": "Для начала выберите, как вы хотите настроить ваш экземпляр Homarr.", + "action": { + "scratch": "Начать с нуля", + "importOldmarr": "Импортировать из Homarr версии до 1.0" + } + }, + "import": { + "title": "Импорт данных", + "subtitle": "Вы можете импортировать данные из существующего экземпляра Homarr.", + "dropzone": { + "title": "Перетащите ZIP-файл сюда или нажмите для его выбора", + "description": "Загруженный ZIP-файл будет обработан, и вы сможете выбрать, что хотите импортировать" + }, + "fileInfo": { + "action": { + "change": "Изменить файл" + } + }, + "importSettings": { + "title": "Настройки импорта", + "description": "Настройте параметры импорта" + }, + "boardSelection": { + "title": "Найдено {count} панелей", + "description": "Выберите все панели с их размерами, которые вы хотите импортировать", + "action": { + "selectAll": "Выбрать все", + "unselectAll": "Снять выбор со всех" + } + }, + "summary": { + "title": "Сводка по импорту", + "description": "В приведенной ниже сводке вы можете увидеть, что будет импортировано", + "action": { + "import": "Подтвердить импорт и продолжить" + }, + "entities": { + "apps": "Приложения", + "boards": "Панели", + "integrations": "Интеграции", + "credentialUsers": "Учетные данные пользователя" + } + }, + "tokenModal": { + "title": "Введите токен импорта", + "field": { + "token": { + "label": "Токен", + "description": "Введите показанный токен импорта из вашего предыдущего экземпляра Homarr" + } + }, + "notification": { + "error": { + "title": "Недействительный токен", + "message": "Введенный токен недействителен" + } + } + } + }, + "user": { + "title": "Администратор системы", + "subtitle": "Укажите учетные данные для администратора системы.", + "notification": { + "success": { + "title": "Пользователь создан", + "message": "Пользователь успешно создан" + }, + "error": { + "title": "Не удалось создать пользователя" + } + } + }, + "group": { + "title": "Внешняя группа", + "subtitle": "Укажите группу, которая будет использоваться для внешних пользователей.", + "form": { + "name": { + "label": "Название группы", + "description": "Название должно соответствовать группе администраторов внешнего провайдера" + } + } + }, + "settings": { + "title": "Настройки", + "subtitle": "Настройте параметры сервера." + }, + "finish": { + "title": "Завершение настройки", + "subtitle": "Всё готово к работе!", + "description": "Вы успешно завершили процесс настройки. Теперь вы можете начать использовать Homarr. Выберите следующее действие:", + "action": { + "goToBoard": "Перейти к панели {name}", + "createBoard": "Создать первую панель", + "inviteUser": "Пригласить других пользователей", + "docs": "Прочитать документацию" + } + } + }, + "backToStart": "Вернуться к началу" + }, "user": { "title": "Пользователи", "name": "Пользователь", "page": { "login": { - "title": "", - "subtitle": "" + "title": "Вход в учётную запись", + "subtitle": "С возвращением! Пожалуйста, введите ваши учётные данные" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "Присоединиться к Homarr", + "subtitle": "Добро пожаловать в Homarr! Пожалуйста, создайте вашу учётную запись", + "description": "Вас пригласил пользователь {username}" }, "init": { - "title": "", - "subtitle": "" + "title": "Новая установка Homarr", + "subtitle": "Пожалуйста, создайте начального пользователя-администратора" } }, "field": { "email": { - "label": "", - "verified": "" + "label": "Электронная почта", + "verified": "Подтверждена" }, "username": { "label": "Имя пользователя" @@ -28,74 +133,84 @@ "password": { "label": "Пароль", "requirement": { - "length": "", - "lowercase": "Включает строчную букву", - "uppercase": "Включает заглавную букву", - "number": "Включает цифру", - "special": "" + "length": "Содержит не менее 8 символов", + "lowercase": "Содержит строчную букву", + "uppercase": "Содержит заглавную букву", + "number": "Содержит цифру", + "special": "Содержит спецсимвол" } }, "passwordConfirm": { - "label": "Подтвердите пароль" + "label": "Подтверждение пароля" }, "previousPassword": { - "label": "" + "label": "Предыдущий пароль" }, "homeBoard": { - "label": "" + "label": "Домашняя панель" }, "pingIconsEnabled": { - "label": "" + "label": "Использовать индикаторы доступности" } }, "error": { - "usernameTaken": "" + "usernameTaken": "Это имя пользователя уже занято" }, "action": { "login": { - "label": "Вход в систему", - "labelWith": "", + "label": "Вход", + "labelWith": "Войти через {provider}", "notification": { "success": { - "title": "", - "message": "" + "title": "Вход выполнен", + "message": "Вы успешно вошли в систему" }, "error": { - "title": "", - "message": "" + "title": "Не удалось войти", + "message": "Не удалось выполнить вход" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "Забыли пароль?", + "description": "Администратор может использовать следующую команду для сброса вашего пароля:" } }, "register": { - "label": "Создать аккаунт", + "label": "Создать учётную запись", "notification": { "success": { - "title": "Аккаунт создан", - "message": "" + "title": "Учётная запись создана", + "message": "Пожалуйста, войдите для продолжения" }, "error": { - "title": "", - "message": "" + "title": "Не удалось создать учётную запись", + "message": "Не удалось создать вашу учётную запись" } } }, - "create": "Создать пользователя", + "create": "Создание пользователя", "changePassword": { - "label": "", + "label": "Изменить пароль", "notification": { "success": { - "message": "" + "message": "Пароль успешно изменён" }, "error": { - "message": "" + "message": "Не удалось изменить пароль" } } }, "changeHomeBoard": { + "notification": { + "success": { + "message": "Домашняя панель успешно изменена" + }, + "error": { + "message": "Не удалось изменить домашнюю панель" + } + } + }, + "changeDefaultSearchEngine": { "notification": { "success": { "message": "" @@ -108,48 +223,48 @@ "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "Первый день недели успешно изменён" }, "error": { - "message": "" + "message": "Не удалось изменить первый день недели" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "Отображение индикаторов доступности успешно изменено" }, "error": { - "message": "" + "message": "Не удалось изменить настройки индикаторов доступности" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Изменить изображение", "notification": { "success": { - "message": "" + "message": "Изображение успешно изменено" }, "error": { - "message": "" + "message": "Не удалось изменить изображение" }, "toLarge": { - "title": "", - "message": "" + "title": "Изображение слишком большое", + "message": "Максимальный размер изображения: {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Удалить изображение", + "confirm": "Вы уверены, что хотите удалить изображение?", "notification": { "success": { - "message": "" + "message": "Изображение успешно удалено" }, "error": { - "message": "" + "message": "Не удалось удалить изображение" } } } @@ -157,63 +272,63 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "Профиль успешно обновлён" }, "error": { - "message": "" + "message": "Не удалось обновить профиль" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "Удалить пользователя навсегда", + "description": "Удаляет этого пользователя вместе с его настройками. Панели не будут удалены. Пользователь не получит уведомление.", + "confirm": "Вы уверены, что хотите удалить пользователя {username} вместе с его настройками?" }, "select": { - "label": "", - "notFound": "" + "label": "Выбрать пользователя", + "notFound": "Пользователь не найден" }, "transfer": { - "label": "" + "label": "Выбрать нового владельца" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "Группы", + "name": "Группа", + "search": "Поиск группы", "field": { - "name": "Имя", - "members": "" + "name": "Название", + "members": "Участники" }, "permission": { "admin": { - "title": "Администратор", + "title": "Администрирование", "item": { "admin": { - "label": "", - "description": "" + "label": "Администратор", + "description": "Участники с этим разрешением имеют полный доступ ко всем функциям и настройкам" } } }, "app": { - "title": "", + "title": "Приложения", "item": { "create": { - "label": "", - "description": "" + "label": "Создание приложений", + "description": "Разрешить участникам создавать приложения" }, "use-all": { - "label": "", - "description": "" + "label": "Использование всех приложений", + "description": "Разрешить участникам добавлять любые приложения на свои панели" }, "modify-all": { - "label": "", - "description": "" + "label": "Изменение всех приложений", + "description": "Разрешить участникам изменять все приложения" }, "full-all": { - "label": "", - "description": "" + "label": "Полный доступ к приложениям", + "description": "Разрешить участникам управлять, использовать и удалять любые приложения" } } }, @@ -221,390 +336,399 @@ "title": "Панели", "item": { "create": { - "label": "", - "description": "" + "label": "Создание панелей", + "description": "Разрешить участникам создавать панели" }, "view-all": { - "label": "", - "description": "" + "label": "Просмотр всех панелей", + "description": "Разрешить участникам просматривать все панели" }, "modify-all": { - "label": "", - "description": "" + "label": "Изменение всех панелей", + "description": "Разрешить участникам изменять все панели (не включает управление доступом и опасную зону)" }, "full-all": { - "label": "", - "description": "" + "label": "Полный доступ к панелям", + "description": "Разрешить участникам просматривать, изменять и удалять все панели (включая управление доступом и опасную зону)" } } }, "integration": { - "title": "", + "title": "Интеграции", "item": { "create": { - "label": "", - "description": "" + "label": "Создание интеграций", + "description": "Разрешить участникам создавать интеграции" }, "use-all": { - "label": "", - "description": "" + "label": "Использование всех интеграций", + "description": "Разрешить участникам добавлять любые интеграции на свои панели" }, "interact-all": { - "label": "", - "description": "" + "label": "Взаимодействие со всеми интеграциями", + "description": "Разрешить участникам взаимодействовать с любыми интеграциями" }, "full-all": { - "label": "", - "description": "" + "label": "Полный доступ к интеграциям", + "description": "Разрешить участникам управлять, использовать и взаимодействовать с любыми интеграциями" } } }, "media": { - "title": "", + "title": "Медиафайлы", "item": { "upload": { - "label": "", - "description": "" + "label": "Загрузка медиафайлов", + "description": "Разрешить участникам загружать медиафайлы" }, "view-all": { - "label": "", - "description": "" + "label": "Полный доступ к медиафайлам", + "description": "Разрешить участникам управлять и удалять любые медиафайлы" }, "full-all": { - "label": "", - "description": "" + "label": "Полный доступ к медиафайлам", + "description": "Разрешить участникам управлять и удалять любыми медиафайлами" } } }, "other": { - "title": "", + "title": "Прочее", "item": { "view-logs": { - "label": "", - "description": "" + "label": "Просмотр логов", + "description": "Разрешить участникам просматривать логи" } } }, "search-engine": { - "title": "", + "title": "Поисковые системы", "item": { "create": { - "label": "", - "description": "" + "label": "Создание поисковых систем", + "description": "Разрешить участникам создавать поисковые системы" }, "modify-all": { - "label": "", - "description": "" + "label": "Изменение всех поисковых систем", + "description": "Разрешить участникам изменять все поисковые системы" }, "full-all": { - "label": "", - "description": "" + "label": "Полный доступ к поисковым системам", + "description": "Разрешить участникам управлять и удалять любые поисковые системы" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "Некоторыми участниками управляет внешняя система аутентификации, их нельзя настроить здесь", + "external": "Всеми участниками управляют внешние системы аутентификации, их нельзя настроить здесь" }, "reservedNotice": { - "message": "" + "message": "Эта группа зарезервирована для системных нужд и имеет ограничения на некоторые действия. " }, "action": { "create": { - "label": "", + "label": "Новая группа", "notification": { "success": { - "message": "" + "message": "Группа успешно создана" }, "error": { - "message": "" + "message": "Не удалось создать группу" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "Передать права владельца", + "description": "Передать права владельца этой группы другому пользователю.", + "confirm": "Вы уверены, что хотите передать права владельца группы {name} пользователю {username}?", "notification": { "success": { - "message": "" + "message": "Группа {group} успешно передана пользователю {user}" }, "error": { - "message": "" + "message": "Не удалось передать права владельца" } } }, "addMember": { - "label": "" + "label": "Добавить участника" }, "removeMember": { - "label": "", - "confirm": "" + "label": "Удалить участника", + "confirm": "Вы уверены, что хотите удалить {user} из этой группы?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "Удалить группу", + "description": "После удаления группы восстановление будет невозможно. Пожалуйста, будьте уверены в своём решении.", + "confirm": "Вы уверены, что хотите удалить группу {name}?", "notification": { "success": { - "message": "" + "message": "Группа {name} успешно удалена" }, "error": { - "message": "" + "message": "Не удалось удалить группу {name}" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "Разрешения сохранены", + "message": "Разрешения успешно сохранены" }, "error": { - "title": "", - "message": "" + "title": "Разрешения не сохранены", + "message": "Не удалось сохранить разрешения" } } }, "update": { "notification": { "success": { - "message": "" + "message": "Группа {name} успешно сохранена" }, "error": { - "message": "" + "message": "Не удалось сохранить группу {name}" } } }, "select": { - "label": "", - "notFound": "" + "label": "Выбрать группу", + "notFound": "Группы не найдены" } } }, "app": { + "search": "", "page": { "list": { "title": "Приложения", "noResults": { - "title": "", - "action": "" + "title": "Приложения пока отсутствуют", + "action": "Создать первое приложение" } }, "create": { - "title": "", + "title": "Новое приложение", "notification": { "success": { - "title": "", - "message": "" + "title": "Приложение создано", + "message": "Приложение успешно создано" }, "error": { - "title": "", - "message": "" + "title": "Не удалось создать", + "message": "Не удалось создать приложение" } } }, "edit": { - "title": "", + "title": "Редактирование приложения", "notification": { "success": { - "title": "", - "message": "" + "title": "Изменения сохранены", + "message": "Приложение успешно сохранено" }, "error": { - "title": "", - "message": "" + "title": "Не удалось сохранить", + "message": "Не удалось сохранить приложение" } } }, "delete": { - "title": "", - "message": "", + "title": "Удаление приложения", + "message": "Вы уверены, что хотите удалить приложение {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "Приложение удалено", + "message": "Приложение успешно удалено" }, "error": { - "title": "", - "message": "" + "title": "Не удалось удалить", + "message": "Не удалось удалить приложение" } } } }, "field": { "name": { - "label": "Имя" + "label": "Название" }, "description": { - "label": "" + "label": "Описание" }, "url": { - "label": "" + "label": "URL-адрес" } }, "action": { "select": { - "label": "", - "notFound": "" + "label": "Выбрать приложение", + "notFound": "Приложения не найдены" } } }, "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "Интеграции", + "search": "Поиск интеграций", "noResults": { - "title": "" + "title": "Интеграции пока отсутствуют" } }, "create": { - "title": "", + "title": "Новая интеграция {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "Интеграция создана", + "message": "Интеграция успешно создана" }, "error": { - "title": "", - "message": "" + "title": "Не удалось создать", + "message": "Не удалось создать интеграцию" } } }, "edit": { - "title": "", + "title": "Редактирование интеграции {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "Изменения сохранены", + "message": "Интеграция успешно сохранена" }, "error": { - "title": "", - "message": "" + "title": "Не удалось сохранить", + "message": "Не удалось сохранить интеграцию" } } }, "delete": { - "title": "", - "message": "", + "title": "Удаление интеграции", + "message": "Вы уверены, что хотите удалить интеграцию {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "Интеграция удалена", + "message": "Интеграция успешно удалена" }, "error": { - "title": "", - "message": "" + "title": "Не удалось удалить", + "message": "Не удалось удалить интеграцию" } } } }, "field": { "name": { - "label": "Имя" + "label": "Название" }, "url": { - "label": "" + "label": "URL-адрес" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { - "create": "" + "create": "Новая интеграция" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "Проверить подключение и создать", + "edit": "Проверить подключение и сохранить" }, - "alertNotice": "", + "alertNotice": "Кнопка сохранения станет доступна после успешного подключения", "notification": { "success": { - "title": "", - "message": "" + "title": "Подключение установлено", + "message": "Подключение успешно установлено" }, "invalidUrl": { - "title": "Неверный URL", - "message": "" + "title": "Недействительный URL-адрес", + "message": "Указан недействительный URL-адрес" }, "secretNotDefined": { - "title": "", - "message": "" + "title": "Отсутствуют учётные данные", + "message": "Не все учётные данные были предоставлены" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "Неверные учётные данные", + "message": "Предоставлены неверные учётные данные" }, "commonError": { - "title": "", - "message": "" + "title": "Ошибка подключения", + "message": "Не удалось установить подключение" }, "badRequest": { - "title": "", - "message": "" + "title": "Неверный запрос", + "message": "Запрос сформирован некорректно" }, "unauthorized": { - "title": "", - "message": "" + "title": "Нет доступа", + "message": "Возможно, указаны неверные учётные данные" }, "forbidden": { - "title": "", - "message": "" + "title": "Доступ запрещён", + "message": "Возможно, недостаточно прав доступа" }, "notFound": { - "title": "", - "message": "" + "title": "Не найдено", + "message": "Возможно, указан неверный URL-адрес или путь" }, "internalServerError": { - "title": "", - "message": "" + "title": "Внутренняя ошибка сервера", + "message": "На сервере произошла ошибка" }, "serviceUnavailable": { - "title": "", - "message": "" + "title": "Сервис недоступен", + "message": "Сервер временно недоступен" }, "connectionAborted": { - "title": "", - "message": "" + "title": "Подключение прервано", + "message": "Подключение было прервано" }, "domainNotFound": { - "title": "", - "message": "" + "title": "Домен не найден", + "message": "Не удалось найти указанный домен" }, "connectionRefused": { - "title": "", - "message": "" + "title": "В подключении отказано", + "message": "В подключении было отказано" }, "invalidJson": { - "title": "", - "message": "" + "title": "Некорректный JSON", + "message": "Ответ сервера содержит некорректный JSON" }, "wrongPath": { - "title": "", - "message": "" + "title": "Неверный путь", + "message": "Возможно, указан неверный путь" } } }, "secrets": { - "title": "", - "lastUpdated": "", - "secureNotice": "", + "title": "Данные авторизации", + "lastUpdated": "Последнее обновление: {date}", + "notSet": { + "label": "Значение не указано", + "tooltip": "Обязательное значение ещё не установлено" + }, + "secureNotice": "Эти данные нельзя будет просмотреть после создания", "reset": { - "title": "", - "message": "" + "title": "Сбросить данные авторизации", + "message": "Вы уверены, что хотите сбросить эти данные авторизации?" }, "noSecretsRequired": { - "segmentTitle": "", - "text": "" + "segmentTitle": "Авторизация не требуется", + "text": "Для этой интеграции не требуются данные авторизации" }, "kind": { "username": { "label": "Имя пользователя", - "newLabel": "" + "newLabel": "Новое имя пользователя" }, "apiKey": { - "label": "", - "newLabel": "" + "label": "API-ключ", + "newLabel": "Новый API-ключ" }, "password": { "label": "Пароль", @@ -613,160 +737,170 @@ } }, "permission": { - "use": "", - "interact": "", - "full": "" + "use": "Подключение сторонних сервисов", + "interact": "Взаимодействие с подключенными сервисами", + "full": "Полное управление интеграциями" } }, "media": { - "plural": "", - "search": "", + "plural": "Медиафайлы", + "search": "Поиск медиафайлов", "field": { - "name": "Имя", + "name": "Название", "size": "Размер", "creator": "Создатель" }, "action": { "upload": { - "label": "", - "file": "", + "label": "Загрузить медиафайл", + "file": "Выбрать файл", "notification": { "success": { - "message": "" + "message": "Медиафайл успешно загружен" }, "error": { - "message": "" + "message": "Не удалось загрузить медиафайл" } } }, "delete": { - "label": "", - "description": "", + "label": "Удалить медиафайл", + "description": "Вы уверены, что хотите удалить медиафайл ?", "notification": { "success": { - "message": "" + "message": "Медиафайл успешно удалён" }, "error": { - "message": "" + "message": "Не удалось удалить медиафайл" } } }, "copy": { - "label": "" + "label": "Копировать URL" } } }, "common": { - "beta": "", + "beta": "Бета", "error": "Ошибка", "action": { "add": "Добавить", "apply": "Применить", - "backToOverview": "", + "backToOverview": "Вернуться к обзору", "create": "Создать", - "edit": "Изменить", - "import": "", + "edit": "Редактировать", + "import": "Импортировать", "insert": "Вставить", "remove": "Удалить", "save": "Сохранить", "saveChanges": "Сохранить изменения", "cancel": "Отмена", "delete": "Удалить", - "discard": "", + "discard": "Отменить", "confirm": "Подтвердить", - "continue": "", - "previous": "Предыдущий", + "continue": "Продолжить", + "previous": "Назад", "next": "Далее", - "checkoutDocs": "", + "checkoutDocs": "Посмотреть документацию", + "checkLogs": "Проверить логи для подробностей", "tryAgain": "Попробовать снова", - "loading": "" + "loading": "Загрузка" }, - "here": "", + "here": "здесь", "iconPicker": { - "label": "", - "header": "" + "label": "URL иконки", + "header": "Введите название или объекты для фильтрации иконок... Homarr найдёт для вас среди {countIcons} иконок." + }, + "colorScheme": { + "options": { + "light": "Светлая", + "dark": "Тёмная" + } }, "information": { - "min": "", - "max": "", - "days": "", - "hours": "Часы", - "minutes": "Минуты" + "min": "Мин.", + "max": "Макс.", + "days": "Дней", + "hours": "Часов", + "minutes": "Минут" }, "notification": { "create": { - "success": "", - "error": "" + "success": "Создание успешно завершено", + "error": "Не удалось создать" }, "delete": { - "success": "", - "error": "" + "success": "Удаление успешно завершено", + "error": "Не удалось удалить" }, "update": { - "success": "", - "error": "" + "success": "Изменения успешно применены", + "error": "Не удалось применить изменения" }, "transfer": { - "success": "", - "error": "" + "success": "Передача успешно завершена", + "error": "Не удалось выполнить передачу" } }, "multiSelect": { - "placeholder": "" + "placeholder": "Выберите одно или несколько значений" }, "multiText": { - "placeholder": "", - "addLabel": "" + "placeholder": "Добавить ещё значения", + "addLabel": "Добавить {value}" }, "select": { - "placeholder": "", + "placeholder": "Выберите значение", "badge": { - "recommended": "" + "recommended": "Рекомендуется" } }, "userAvatar": { "menu": { - "switchToDarkMode": "", - "switchToLightMode": "", - "management": "", - "preferences": "Ваши настройки", - "logout": "", - "login": "Вход в систему", - "homeBoard": "", - "loggedOut": "" + "switchToDarkMode": "Переключить на тёмную тему", + "switchToLightMode": "Переключить на светлую тему", + "management": "Управление", + "preferences": "Настройки", + "logout": "Выйти", + "login": "Вход", + "homeBoard": "Ваша домашняя панель", + "loggedOut": "Выход выполнен", + "updateAvailable": "Доступно {countUpdates} обновлений: {tag}" } }, - "dangerZone": "Зона опасности", - "noResults": "Результаты не найдены", + "dangerZone": "Опасная зона", + "noResults": "Ничего не найдено", "preview": { - "show": "", - "hide": "" + "show": "Показать предпросмотр", + "hide": "Скрыть предпросмотр" }, "zod": { "errors": { - "default": "Данное поле недействительно", - "required": "Это поле обязательно", + "default": "Поле заполнено неверно", + "required": "Это поле обязательно для заполнения", "string": { - "startsWith": "Значение данного поля должно начинаться с {startsWith}", - "endsWith": "Значение данного поля должно заканчиваться на {endsWith}", - "includes": "Значение данного поля должно включать {includes}", - "invalidEmail": "" + "startsWith": "Поле должно начинаться с {startsWith}", + "endsWith": "Поле должно заканчиваться на {endsWith}", + "includes": "Поле должно содержать {includes}", + "invalidEmail": "Поле должно содержать корректный email" }, "tooSmall": { - "string": "Данное поле должно содержать не менее {minimum} символов", - "number": "Значение данного поля должно быть больше или равно {minimum}" + "string": "Поле должно содержать не менее {minimum} символов", + "number": "Значение должно быть больше или равно {minimum}" }, "tooBig": { - "string": "Данное поле должно содержать не более {maximum} символов", - "number": "Значение этого поля должно быть меньше или равно {maximum}" + "string": "Поле должно содержать не более {maximum} символов", + "number": "Значение должно быть меньше или равно {maximum}" }, "custom": { - "passwordsDoNotMatch": "", - "passwordRequirements": "", - "boardAlreadyExists": "", - "invalidFileType": "", - "fileTooLarge": "", - "invalidConfiguration": "" + "passwordsDoNotMatch": "Пароли не совпадают", + "passwordRequirements": "Пароль не соответствует требованиям", + "boardAlreadyExists": "Панель с таким именем уже существует", + "invalidFileType": "Неверный тип файла, ожидается {expected}", + "invalidFileName": "", + "fileTooLarge": "Файл слишком большой, максимальный размер {maxSize}", + "invalidConfiguration": "Неверная конфигурация", + "groupNameTaken": "Имя группы уже занято" } } } @@ -774,57 +908,57 @@ "section": { "dynamic": { "action": { - "create": "", - "remove": "" + "create": "Новый динамический элемент", + "remove": "Удалить динамический элемент" }, "remove": { - "title": "", - "message": "" + "title": "Удалить динамический элемент", + "message": "Вы уверены, что хотите удалить этот динамический элемент? Содержимое будет перемещено в то же место в родительском элементе." } }, "category": { "field": { "name": { - "label": "Имя" + "label": "Название" } }, "action": { - "create": "", - "edit": "", - "remove": "", + "create": "Новая категория", + "edit": "Переименовать категорию", + "remove": "Удалить категорию", "moveUp": "Переместить вверх", "moveDown": "Переместить вниз", - "createAbove": "", - "createBelow": "" + "createAbove": "Создать категорию выше", + "createBelow": "Создать категорию ниже" }, "create": { - "title": "", - "submit": "" + "title": "Новая категория", + "submit": "Добавить категорию" }, "remove": { - "title": "", - "message": "" + "title": "Удалить категорию", + "message": "Вы уверены, что хотите удалить категорию {name}?" }, "edit": { - "title": "", - "submit": "" + "title": "Переименовать категорию", + "submit": "Переименовать категорию" }, "menu": { "label": { - "create": "", - "changePosition": "Изменить положение" + "create": "Новая категория", + "changePosition": "Изменить позицию" } } } }, "item": { "action": { - "create": "", - "import": "", - "edit": "", - "moveResize": "", - "duplicate": "", - "remove": "" + "create": "Новый элемент", + "import": "Импортировать элемент", + "edit": "Редактировать элемент", + "moveResize": "Переместить / изменить размер", + "duplicate": "Дублировать элемент", + "remove": "Удалить элемент" }, "menu": { "label": { @@ -832,11 +966,12 @@ } }, "create": { - "title": "", - "addToBoard": "" + "title": "Выберите тип элемента", + "search": "", + "addToBoard": "Добавить на панель" }, "moveResize": { - "title": "", + "title": "Переместить / изменить размер элемента", "field": { "width": { "label": "Ширина" @@ -845,224 +980,244 @@ "label": "Высота" }, "xOffset": { - "label": "" + "label": "Смещение по X" }, "yOffset": { - "label": "" + "label": "Смещение по Y" } } }, "edit": { - "title": "", + "title": "Редактировать элемент", "advancedOptions": { - "label": "", - "title": "" + "label": "Расширенные настройки", + "title": "Расширенные настройки элемента" }, "field": { "integrations": { - "label": "" + "label": "Интеграции" }, "customCssClasses": { - "label": "" + "label": "Пользовательские CSS классы" } } }, "remove": { - "title": "", - "message": "" + "title": "Удалить элемент", + "message": "Вы уверены, что хотите удалить этот элемент?" } }, "widget": { "app": { - "name": "", - "description": "", + "name": "Приложение", + "description": "Встраивает приложение в панель.", "option": { "appId": { - "label": "" + "label": "Выберите приложение" }, "openInNewTab": { - "label": "Открыть в новой вкладке" + "label": "Открывать в новой вкладке" }, "showTitle": { - "label": "" + "label": "Показывать название приложения" }, "showDescriptionTooltip": { - "label": "" + "label": "Показывать всплывающую подсказку с описанием" }, "pingEnabled": { - "label": "" + "label": "Включить простую проверку доступности" } }, "error": { "notFound": { - "label": "", - "tooltip": "" + "label": "Нет приложения", + "tooltip": "Не выбрано корректное приложение" } } }, "bookmarks": { + "name": "Закладки", + "description": "Отображает несколько ссылок на приложение", + "option": { + "title": { + "label": "Заголовок" + }, + "layout": { + "label": "Расположение", + "option": { + "row": { + "label": "Горизонтально" + }, + "column": { + "label": "Вертикально" + }, + "grid": { + "label": "Сетка" + } + } + }, + "items": { + "label": "Закладки", + "add": "Добавить закладку" + } + } + }, + "dnsHoleSummary": { + "name": "Сводка DNS-фильтра", + "description": "Отображает сводную информацию о вашем DNS-фильтре", + "option": { + "layout": { + "label": "Расположение", + "option": { + "row": { + "label": "Горизонтально" + }, + "column": { + "label": "Вертикально" + }, + "grid": { + "label": "Сетка" + } + } + }, + "usePiHoleColors": { + "label": "Использовать цвета Pi-hole" + } + }, + "error": { + "internalServerError": "Не удалось получить сводку DNS-фильтра", + "integrationsDisconnected": "Нет данных, все интеграции отключены" + }, + "data": { + "adsBlockedToday": "заблокировано сегодня", + "adsBlockedTodayPercentage": "заблокировано сегодня", + "dnsQueriesToday": "DNS-запросов сегодня", + "domainsBeingBlocked": "Доменов в списке блокировки" + }, + "domainsTooltip": "" + }, + "dnsHoleControls": { + "name": "Управление DNS-фильтром", + "description": "Управляйте PiHole или AdGuard прямо с вашей панели", + "option": { + "layout": { + "label": "Расположение", + "option": { + "row": { + "label": "Горизонтально" + }, + "column": { + "label": "Вертикально" + }, + "grid": { + "label": "Сетка" + } + } + }, + "showToggleAllButtons": { + "label": "Показывать кнопки управления защитой" + } + }, + "error": { + "internalServerError": "Не удалось управлять DNS-фильтром" + }, + "controls": { + "enableAll": "Включить защиту", + "disableAll": "Отключить защиту", + "setTimer": "Установить таймер", + "set": "Установить", + "enabled": "Включено", + "disabled": "Отключено", + "processing": "Обработка", + "disconnected": "Отключено", + "hours": "Часы", + "minutes": "Минуты", + "unlimited": "Оставить пустым для неограниченного времени" + } + }, + "clock": { + "name": "Дата и время", + "description": "Отображает текущую дату и время.", + "option": { + "customTitleToggle": { + "label": "Настроить отображение заголовка/города", + "description": "Показывать настраиваемый заголовок или название города/страны над часами." + }, + "customTitle": { + "label": "Заголовок" + }, + "is24HourFormat": { + "label": "24-часовой формат", + "description": "Использовать 24-часовой формат вместо 12-часового" + }, + "showSeconds": { + "label": "Показывать секунды" + }, + "useCustomTimezone": { + "label": "Использовать другой часовой пояс" + }, + "timezone": { + "label": "Часовой пояс", + "description": "Выберите часовой пояс согласно стандарту IANA" + }, + "showDate": { + "label": "Показывать дату" + }, + "dateFormat": { + "label": "Формат даты", + "description": "Как должна выглядеть дата" + } + } + }, + "minecraftServerStatus": { "name": "", "description": "", "option": { "title": { "label": "" }, - "layout": { - "label": "", - "option": { - "row": { - "label": "" - }, - "column": { - "label": "" - }, - "grid": { - "label": "" - } - } + "domain": { + "label": "" }, - "items": { - "label": "", - "add": "" - } - } - }, - "dnsHoleSummary": { - "name": "", - "description": "", - "option": { - "layout": { - "label": "Макет", - "option": { - "row": { - "label": "Горизонтальный" - }, - "column": { - "label": "Вертикальный" - }, - "grid": { - "label": "" - } - } - }, - "usePiHoleColors": { + "isBedrockServer": { "label": "" } }, - "error": { - "internalServerError": "", - "integrationsDisconnected": "" - }, - "data": { - "adsBlockedToday": "Заблокировано сегодня", - "adsBlockedTodayPercentage": "Заблокировано сегодня", - "dnsQueriesToday": "запросов сегодня", - "domainsBeingBlocked": "" - } - }, - "dnsHoleControls": { - "name": "", - "description": "Управляйте PiHole или AdGuard прямо с вашей панели", - "option": { - "layout": { - "label": "Макет", - "option": { - "row": { - "label": "Горизонтальный" - }, - "column": { - "label": "Вертикальный" - }, - "grid": { - "label": "" - } - } - }, - "showToggleAllButtons": { - "label": "" - } - }, - "error": { - "internalServerError": "" - }, - "controls": { - "enableAll": "", - "disableAll": "", - "setTimer": "", - "set": "Установить", - "enabled": "Включено", - "disabled": "Отключено", - "processing": "", - "disconnected": "", - "hours": "Часы", - "minutes": "Минуты", - "unlimited": "" - } - }, - "clock": { - "name": "", - "description": "Отображает текущую дату и время.", - "option": { - "customTitleToggle": { - "label": "", - "description": "" - }, - "customTitle": { - "label": "" - }, - "is24HourFormat": { - "label": "", - "description": "" - }, - "showSeconds": { - "label": "" - }, - "useCustomTimezone": { - "label": "" - }, - "timezone": { - "label": "Часовой пояс", - "description": "" - }, - "showDate": { - "label": "" - }, - "dateFormat": { - "label": "", - "description": "" - } + "status": { + "online": "", + "offline": "" } }, "notebook": { - "name": "Блокнот", - "description": "", + "name": "Заметки", + "description": "Простой виджет заметок с поддержкой markdown", "option": { "showToolbar": { - "label": "Показать панель инструментов для написания текста с использованием разметки Markdown" + "label": "Показывать панель инструментов для редактирования markdown" }, "allowReadOnlyCheck": { - "label": "Разрешить проверку в режиме \"только для чтения\"" + "label": "Разрешить отмечать пункты в режиме чтения" }, "content": { - "label": "Содержимое блокнота" + "label": "Содержимое заметок" } }, "controls": { "bold": "Жирный", "italic": "Курсив", - "strikethrough": "Зачеркнутый", - "underline": "Подчеркнутый", + "strikethrough": "Зачёркнутый", + "underline": "Подчёркнутый", "colorText": "Цвет текста", - "colorHighlight": "Выделение текста цветом", + "colorHighlight": "Цвет выделения текста", "code": "Код", "clear": "Очистить форматирование", "heading": "Заголовок {level}", - "align": "Выровнять текст: {position}", + "align": "Выравнивание текста: {position}", "blockquote": "Цитата", "horizontalLine": "Горизонтальная линия", "bulletList": "Маркированный список", "orderedList": "Нумерованный список", - "checkList": "Чек-лист", + "checkList": "Список с чекбоксами", "increaseIndent": "Увеличить отступ", "decreaseIndent": "Уменьшить отступ", "link": "Ссылка", @@ -1071,18 +1226,18 @@ "addTable": "Добавить таблицу", "deleteTable": "Удалить таблицу", "colorCell": "Цвет ячейки", - "mergeCell": "Переключить объединение ячеек", - "addColumnLeft": "Добавить столбец перед", - "addColumnRight": "Добавить столбец после", + "mergeCell": "Объединить/разделить ячейки", + "addColumnLeft": "Добавить столбец слева", + "addColumnRight": "Добавить столбец справа", "deleteColumn": "Удалить столбец", - "addRowTop": "Добавить строку перед", - "addRowBelow": "Добавить строку после", + "addRowTop": "Добавить строку сверху", + "addRowBelow": "Добавить строку снизу", "deleteRow": "Удалить строку" }, "align": { - "left": "Слева", + "left": "По левому краю", "center": "По центру", - "right": "Справа" + "right": "По правому краю" }, "popover": { "clearColor": "Очистить цвет", @@ -1095,11 +1250,11 @@ } }, "iframe": { - "name": "", - "description": "Встраиваемое содержимое из интернета. Некоторые веб-сайты могут ограничивать доступ.", + "name": "iFrame", + "description": "Встраивает любой контент из интернета. Некоторые сайты могут ограничивать доступ.", "option": { "embedUrl": { - "label": "URL-адрес на встраивание" + "label": "URL для встраивания" }, "allowFullScreen": { "label": "Разрешить полноэкранный режим" @@ -1114,7 +1269,7 @@ "label": "Разрешить оплату" }, "allowAutoPlay": { - "label": "Разрешить авто воспроизведение" + "label": "Разрешить автовоспроизведение" }, "allowMicrophone": { "label": "Разрешить микрофон" @@ -1127,31 +1282,32 @@ } }, "error": { - "noUrl": "", - "noBrowerSupport": "Ваш браузер не поддерживает iframes. Пожалуйста, обновите свой браузер." + "noUrl": "URL для iFrame не указан", + "unsupportedProtocol": "", + "noBrowerSupport": "Ваш браузер не поддерживает iframes. Пожалуйста, обновите браузер." } }, "smartHome-entityState": { - "name": "", - "description": "", + "name": "Состояние объекта", + "description": "Отображает состояние объекта и позволяет управлять им при необходимости", "option": { "entityId": { "label": "ID объекта" }, "displayName": { - "label": "" + "label": "Отображаемое имя" }, "entityUnit": { - "label": "" + "label": "Единица измерения" }, "clickable": { - "label": "" + "label": "Кликабельный" } } }, "smartHome-executeAutomation": { - "name": "", - "description": "", + "name": "Запуск автоматизации", + "description": "Запускает автоматизацию одним нажатием", "option": { "displayName": { "label": "Отображаемое имя" @@ -1161,64 +1317,64 @@ } }, "spotlightAction": { - "run": "" + "run": "Запустить {name}" } }, "calendar": { "name": "Календарь", - "description": "", + "description": "Отображает события из ваших интеграций в календаре в определённом временном периоде", "option": { "releaseType": { - "label": "Тип релиза в Radarr", + "label": "Тип релиза Radarr", "options": { - "inCinemas": "", - "digitalRelease": "", - "physicalRelease": "" + "inCinemas": "В кинотеатрах", + "digitalRelease": "Цифровой релиз", + "physicalRelease": "Физический релиз" } }, "filterPastMonths": { - "label": "" + "label": "Начиная с" }, "filterFutureMonths": { - "label": "" + "label": "Заканчивая" } } }, "weather": { "name": "Погода", - "description": "Отображает текущую информацию о погоде для заданного местоположения.", + "description": "Отображает текущую информацию о погоде для указанного местоположения.", "option": { "isFormatFahrenheit": { - "label": "" + "label": "Температура в градусах Фаренгейта" }, "location": { "label": "Местоположение" }, "showCity": { - "label": "" + "label": "Показывать город" }, "hasForecast": { - "label": "" + "label": "Показывать прогноз" }, "forecastDayCount": { - "label": "", - "description": "" + "label": "Количество дней прогноза", + "description": "Если виджет недостаточно широкий, будет показано меньше дней" }, "dateFormat": { - "label": "", - "description": "" + "label": "Формат даты", + "description": "Как должна отображаться дата" } }, "kind": { "clear": "Ясно", - "mainlyClear": "Малооблачно", + "mainlyClear": "Преимущественно ясно", "fog": "Туман", "drizzle": "Морось", - "freezingDrizzle": "Изморозь, возможен гололёд", + "freezingDrizzle": "Изморозь", "rain": "Дождь", "freezingRain": "Моросящий дождь", "snowFall": "Снегопад", - "snowGrains": "Снежные зерна", + "snowGrains": "Снежная крупа", "rainShowers": "Ливень", "snowShowers": "Снегопад", "thunderstorm": "Гроза", @@ -1227,25 +1383,25 @@ } }, "indexerManager": { - "name": "Статус менеджера индексаторов", - "description": "", + "name": "Состояние индексаторов", + "description": "Статус ваших индексаторов", "option": { "openIndexerSiteInNewTab": { - "label": "" + "label": "Открывать сайт индексатора в новой вкладке" } }, - "title": "Статус менеджера индексаторов", - "testAll": "Тестировать все", + "title": "Индексаторы", + "testAll": "Проверить все", "error": { - "internalServerError": "" + "internalServerError": "Не удалось получить статус индексаторов" } }, "healthMonitoring": { "name": "Мониторинг состояния системы", - "description": "Отображает информацию о состоянии и статусе вашей системы(систем).", + "description": "Отображает информацию о состоянии и работоспособности вашей системы (систем).", "option": { "fahrenheit": { - "label": "Температура процессора в градусах Фаренгейта" + "label": "Температура CPU в градусах Фаренгейта" }, "cpu": { "label": "Показывать информацию о процессоре" @@ -1258,41 +1414,41 @@ } }, "popover": { - "information": "", - "processor": "", - "memory": "", - "memoryAvailable": "", - "version": "", - "uptime": "", - "loadAverage": "", - "minute": "", - "minutes": "", - "used": "", - "available": "Доступен", - "lastSeen": "" + "information": "Информация", + "processor": "Процессор: {cpuModelName}", + "memory": "Память: {memory}GiB", + "memoryAvailable": "Доступно: {memoryAvailable}GiB ({percent}%)", + "version": "Версия: {version}", + "uptime": "Время работы: {months} мес., {days} дн., {hours} ч., {minutes} мин.", + "loadAverage": "Средняя нагрузка:", + "minute": "1 минута", + "minutes": "{count} минут", + "used": "Использовано", + "available": "Доступно", + "lastSeen": "Последнее обновление: {lastSeen}" }, "memory": {}, "error": { - "internalServerError": "" + "internalServerError": "Не удалось получить данные о состоянии системы" } }, "common": { "location": { - "query": "", - "latitude": "", - "longitude": "", - "disabledTooltip": "", - "unknownLocation": "", + "query": "Город / Почтовый индекс", + "latitude": "Широта", + "longitude": "Долгота", + "disabledTooltip": "Пожалуйста, введите город или почтовый индекс", + "unknownLocation": "Неизвестное местоположение", "search": "Поиск", "table": { "header": { - "city": "", - "country": "", - "coordinates": "", - "population": "" + "city": "Город", + "country": "Страна", + "coordinates": "Координаты", + "population": "Население" }, "action": { - "select": "" + "select": "Выбрать {city}, {countryCode}" }, "population": { "fallback": "Неизвестно" @@ -1300,265 +1456,328 @@ } }, "integration": { - "noData": "", - "description": "" + "noData": "Интеграции не найдены", + "description": "Нажмите , чтобы создать новую интеграцию" }, "app": { - "noData": "", - "description": "" + "noData": "Приложения не найдены", + "description": "Нажмите , чтобы создать новое приложение" }, "error": { - "action": { - "logs": "" - }, - "noIntegration": "", - "noData": "" + "noIntegration": "Интеграция не выбрана", + "noData": "Данные интеграции недоступны" }, "option": {} }, "video": { - "name": "Трансляция видео", - "description": "Встраивание видео или прямой трансляции видео с камеры или веб-сайта", + "name": "Видеотрансляция", + "description": "Встраивает видео с камеры или трансляцию с веб-сайта", "option": { "feedUrl": { - "label": "URL-адрес потока" + "label": "URL трансляции" }, "hasAutoPlay": { "label": "Автовоспроизведение", - "description": "" + "description": "Автовоспроизведение работает только при отключенном звуке из-за ограничений браузера" }, "isMuted": { - "label": "" + "label": "Без звука" }, "hasControls": { - "label": "" + "label": "Показывать элементы управления" } }, "error": { - "noUrl": "", - "forYoutubeUseIframe": "" + "noUrl": "URL видео не указан", + "forYoutubeUseIframe": "Для видео с YouTube используйте виджет iframe" } }, "mediaServer": { - "name": "", - "description": "", - "option": {} + "name": "Активные просмотры", + "description": "Отображает текущие сеансы воспроизведения на медиасерверах", + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { - "name": "", - "description": "", + "name": "Загрузки", + "description": "Позволяет просматривать и управлять загрузками как из торрент-клиентов, так и из Usenet-клиентов.", "option": { "columns": { - "label": "" + "label": "Отображаемые столбцы" }, "enableRowSorting": { - "label": "" + "label": "Включить сортировку элементов" }, "defaultSort": { - "label": "" + "label": "Столбец для сортировки по умолчанию" }, "descendingDefaultSort": { - "label": "" + "label": "Обратная сортировка" }, "showCompletedUsenet": { - "label": "" + "label": "Показывать завершённые задачи Usenet" }, "showCompletedTorrent": { - "label": "" + "label": "Показывать завершённые торренты" }, "activeTorrentThreshold": { - "label": "" + "label": "Скрывать завершённые торренты ниже этого порога (в КиБ/с)" }, "categoryFilter": { - "label": "" + "label": "Фильтр по категориям/меткам" }, "filterIsWhitelist": { - "label": "" + "label": "Использовать фильтр как белый список" }, "applyFilterToRatio": { - "label": "" + "label": "Использовать фильтр при расчёте рейтинга" } }, "errors": { - "noColumns": "", - "noCommunications": "" + "noColumns": "Выберите столбцы в настройках элементов", + "noCommunications": "Не удалось загрузить данные из интеграции" }, "items": { "actions": { - "columnTitle": "" + "columnTitle": "Управление" }, "added": { - "columnTitle": "", + "columnTitle": "Добавлено", "detailsTitle": "Дата добавления" }, "category": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Дополнительно", + "detailsTitle": "Категории (или дополнительная информация)" }, "downSpeed": { "columnTitle": "Загрузка", - "detailsTitle": "Скорость скачивания" + "detailsTitle": "Скорость загрузки" }, "index": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "#", + "detailsTitle": "Текущий индекс в клиенте" }, "id": { - "columnTitle": "" + "columnTitle": "Id" }, "integration": { "columnTitle": "Интеграция" }, "name": { - "columnTitle": "" + "columnTitle": "Название задачи" }, "progress": { "columnTitle": "Прогресс", - "detailsTitle": "" + "detailsTitle": "Прогресс загрузки" }, "ratio": { "columnTitle": "Рейтинг", - "detailsTitle": "" + "detailsTitle": "Рейтинг торрента (получено/отдано)" }, "received": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Всего загружено", + "detailsTitle": "Всего загружено" }, "sent": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Всего отдано", + "detailsTitle": "Всего отдано" }, "size": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Размер файла", + "detailsTitle": "Общий размер выбранного/файлов" }, "state": { "columnTitle": "Состояние", - "detailsTitle": "" + "detailsTitle": "Состояние задачи" }, "time": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Время завершения", + "detailsTitle": "Время с/до завершения" }, "type": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Тип", + "detailsTitle": "Тип клиента загрузки" }, "upSpeed": { "columnTitle": "Отдача", - "detailsTitle": "" + "detailsTitle": "Скорость отдачи" } }, "states": { - "downloading": "Скачивается", - "queued": "Очередь", + "downloading": "Загрузка", + "queued": "В очереди", "paused": "Приостановлено", "completed": "Завершено", - "failed": "", - "processing": "", - "leeching": "", - "stalled": "", + "failed": "Ошибка", + "processing": "Обработка", + "leeching": "Скачивание", + "stalled": "Простаивает", "unknown": "Неизвестно", - "seeding": "" + "seeding": "Раздача" }, "actions": { "clients": { - "modalTitle": "", - "pause": "", - "resume": "" + "modalTitle": "Клиенты", + "pause": "Приостановить все клиенты/задачи", + "resume": "Возобновить все клиенты/задачи" }, "client": { - "pause": "", - "resume": "" + "pause": "Приостановить клиент", + "resume": "Возобновить клиент" }, "item": { - "pause": "", - "resume": "", + "pause": "Приостановить задачу", + "resume": "Возобновить задачу", "delete": { - "title": "", - "modalTitle": "", - "entry": "", - "entryAndFiles": "" + "title": "Удалить задачу", + "modalTitle": "Вы уверены, что хотите удалить эту задачу?", + "entry": "Удалить запись", + "entryAndFiles": "Удалить запись и файл(ы)" } } }, - "globalRatio": "" + "globalRatio": "Общий рейтинг" }, "mediaRequests-requestList": { - "name": "", - "description": "Просмотреть список всех медиа-запросов из вашего экземпляра Overseerr или Jellyseerr", + "name": "Запросы медиаконтента", + "description": "Список всех запросов на добавление медиаконтента из вашего экземпляра Overseerr или Jellyseerr", "option": { "linksTargetNewTab": { "label": "Открывать ссылки в новой вкладке" } }, "pending": { - "approve": "", - "approving": "", - "decline": "" + "approve": "Одобрить запрос", + "approving": "Одобрение запроса...", + "decline": "Отклонить запрос" }, "availability": { "unknown": "Неизвестно", - "pending": "", - "processing": "", - "partiallyAvailable": "Частично", - "available": "Доступен" + "pending": "В ожидании", + "processing": "Обработка", + "partiallyAvailable": "Частично доступно", + "available": "Доступно" }, - "toBeDetermined": "" + "toBeDetermined": "Будет определено позже" }, "mediaRequests-requestStats": { - "name": "", - "description": "Статистика ваших медиазапросов", + "name": "Статистика запросов медиаконтента", + "description": "Статистика по запросам медиаконтента", "option": {}, "titles": { "stats": { - "main": "Статистика медиа", + "main": "Статистика медиаконтента", "approved": "Уже одобрено", - "pending": "Ожидающие утверждения", - "processing": "", - "declined": "", - "available": "", + "pending": "Ожидает одобрения", + "processing": "Обрабатывается", + "declined": "Уже отклонено", + "available": "Уже доступно", "tv": "Запросы сериалов", "movie": "Запросы фильмов", "total": "Всего" }, "users": { "main": "Топ пользователей", - "requests": "" + "requests": "Запросы" + } + } + }, + "mediaTranscoding": { + "name": "Перекодирование медиа", + "description": "Статистика, текущая очередь и состояние обработчиков перекодирования медиафайлов", + "option": { + "defaultView": { + "label": "Вид по умолчанию" + }, + "queuePageSize": { + "label": "Размер страницы очереди" + } + }, + "tab": { + "workers": "Обработчики", + "queue": "Очередь", + "statistics": "Статистика" + }, + "currentIndex": "{start}-{end} из {total}", + "healthCheck": { + "title": "Проверка работоспособности", + "queued": "В очереди", + "status": { + "healthy": "Исправно", + "unhealthy": "Неисправно" + } + }, + "panel": { + "statistics": { + "empty": "Пусто", + "transcodes": "Перекодировано", + "transcodesCount": "Перекодировано: {value}", + "healthChecksCount": "Проверок: {value}", + "filesCount": "Файлов: {value}", + "savedSpace": "Сэкономлено места: {value}", + "healthChecks": "Проверки работоспособности", + "videoCodecs": "Кодеки", + "videoContainers": "Контейнеры", + "videoResolutions": "Разрешения" + }, + "workers": { + "empty": "Пусто", + "table": { + "file": "Файл", + "eta": "Осталось", + "progress": "Прогресс", + "transcode": "Перекодирование", + "healthCheck": "Проверка" + } + }, + "queue": { + "empty": "Пусто", + "table": { + "file": "Файл", + "size": "Размер", + "transcode": "Перекодирование", + "healthCheck": "Проверка" + } } } }, "rssFeed": { - "name": "", - "description": "", + "name": "RSS-ленты", + "description": "Отслеживание и отображение одной или нескольких RSS, ATOM или JSON-лент", "option": { "feedUrls": { - "label": "" + "label": "URL-адреса лент" }, "enableRtl": { - "label": "" + "label": "Включить режим RTL" }, "textLinesClamp": { - "label": "" + "label": "Ограничение строк описания" }, "maximumAmountPosts": { - "label": "" + "label": "Максимальное количество записей" } } } }, "widgetPreview": { "toggle": { - "enabled": "", - "disabled": "" + "enabled": "Режим редактирования включён", + "disabled": "Режим редактирования отключён" }, "dimensions": { - "title": "" + "title": "Изменить размеры" } }, "board": { "action": { - "edit": { + "duplicate": { + "title": "", + "message": "", "notification": { "success": { "title": "", @@ -1568,45 +1787,58 @@ "title": "", "message": "" } + } + }, + "edit": { + "notification": { + "success": { + "title": "Изменения применены", + "message": "Панель успешно сохранена" + }, + "error": { + "title": "Не удалось применить изменения", + "message": "Не удалось сохранить панель" + } }, "confirmLeave": { - "title": "", - "message": "" + "title": "Несохранённые изменения", + "message": "У вас есть несохранённые изменения. Вы уверены, что хотите выйти?" } }, "oldImport": { - "label": "", + "label": "Импорт из версии Homarr до 1.0.0", "notification": { "success": { - "title": "", - "message": "" + "title": "Импорт успешно выполнен", + "message": "Панель успешно импортирована" }, "error": { - "title": "", - "message": "" + "title": "Импорт не удался", + "message": "Не удалось импортировать панель, проверьте логи для дополнительной информации" } }, "form": { "file": { - "label": "", - "invalidError": "" + "label": "Выберите JSON-файл", + "invalidError": "Недействительный файл конфигурации" }, "apps": { "label": "Приложения", "avoidDuplicates": { - "label": "", - "description": "" + "label": "Избегать дубликатов", + "description": "Игнорирует приложения, для которых уже существует приложение с тем же URL-адресом" }, "onlyImportApps": { - "label": "", - "description": "" + "label": "Импортировать только приложения", + "description": "Добавляет только приложения, панель нужно будет создать заново вручную" } }, "name": { - "label": "" + "label": "Название панели" }, "screenSize": { - "label": "", + "label": "Размер экрана", + "description": "В версиях до 1.0 существовало три разных режима, поэтому вы могли выбрать количество столбцов для каждого размера экрана.", "option": { "sm": "Маленький", "md": "Средний", @@ -1614,16 +1846,16 @@ } }, "sidebarBehavior": { - "label": "", - "description": "", + "label": "Поведение боковых панелей", + "description": "Боковые панели были удалены в версии 1.0, вы можете выбрать, что должно произойти с элементами внутри них.", "option": { "lastSection": { - "label": "", - "description": "" + "label": "Последний раздел", + "description": "Боковая панель будет отображаться под последним разделом" }, "removeItems": { - "label": "", - "description": "" + "label": "Удалить элементы", + "description": "Элементы, содержащиеся в боковой панели, будут удалены" } } } @@ -1632,51 +1864,51 @@ }, "field": { "pageTitle": { - "label": "" + "label": "Заголовок страницы" }, "metaTitle": { - "label": "" + "label": "Мета-заголовок" }, "logoImageUrl": { - "label": "" + "label": "URL изображения логотипа" }, "faviconImageUrl": { - "label": "" + "label": "URL изображения favicon" }, "backgroundImageUrl": { - "label": "" + "label": "URL фонового изображения" }, "backgroundImageAttachment": { - "label": "Закрепление фонового изображения", + "label": "Поведение фонового изображения", "option": { "fixed": { - "label": "", - "description": "" + "label": "Фиксированное", + "description": "Фон остаётся на одном месте при прокрутке." }, "scroll": { - "label": "", - "description": "" + "label": "Прокручиваемое", + "description": "Фон прокручивается вместе со страницей." } } }, "backgroundImageRepeat": { - "label": "", + "label": "Повторение фонового изображения", "option": { "repeat": { - "label": "", - "description": "" + "label": "Повторять", + "description": "Изображение повторяется столько раз, сколько необходимо для заполнения всей области фона." }, "no-repeat": { - "label": "", - "description": "" + "label": "Не повторять", + "description": "Изображение не повторяется и может не заполнить всё пространство." }, "repeat-x": { - "label": "", - "description": "" + "label": "Повторять по горизонтали", + "description": "То же, что и 'Повторять', но только по горизонтальной оси." }, "repeat-y": { - "label": "", - "description": "" + "label": "Повторять по вертикали", + "description": "То же, что и 'Повторять', но только по вертикальной оси." } } }, @@ -1684,12 +1916,12 @@ "label": "Размер фонового изображения", "option": { "cover": { - "label": "", - "description": "" + "label": "Заполнение", + "description": "Масштабирует изображение с сохранением пропорций так, чтобы оно целиком заполнило область, обрезая излишки." }, "contain": { - "label": "", - "description": "" + "label": "Уместить", + "description": "Масштабирует изображение с сохранением пропорций так, чтобы оно полностью поместилось в область без обрезки." } } }, @@ -1700,155 +1932,188 @@ "label": "Дополнительный цвет" }, "opacity": { - "label": "" + "label": "Прозрачность" }, "customCss": { - "label": "", - "description": "Дополнительная настройка вашей панели с использованием CSS, рекомендуется только опытным пользователям", + "label": "Пользовательский CSS для этой панели", + "description": "Дополнительная настройка вашей панели с помощью CSS, рекомендуется только опытным пользователям", "customClassesAlert": { - "title": "", - "description": "" + "title": "Пользовательские классы", + "description": "Вы можете добавлять пользовательские классы к элементам панели в расширенных настройках каждого элемента и использовать их в пользовательском CSS выше." } }, "columnCount": { - "label": "" + "label": "Количество столбцов" }, "name": { - "label": "Имя" + "label": "Название" }, "isPublic": { - "label": "Публичный", - "description": "" + "label": "Публичная", + "description": "Публичные панели доступны всем, даже без учётной записи." } }, "content": { - "metaTitle": "" + "metaTitle": "Панель {boardName}" }, "setting": { - "title": "", + "title": "Настройки панели {boardName}", "section": { "general": { "title": "Общие", - "unrecognizedLink": "" + "unrecognizedLink": "Указанная ссылка не распознана и не будет показана в предпросмотре, но может всё ещё работать." }, "layout": { - "title": "Макет" + "title": "Компоновка" }, "background": { "title": "Фон" }, "color": { - "title": "" + "title": "Цвета" }, "customCss": { - "title": "" + "title": "Пользовательский CSS" }, "access": { - "title": "", + "title": "Управление доступом", "permission": { "item": { "view": { "label": "Просмотр панели" }, "modify": { - "label": "" + "label": "Изменение панели" }, "full": { - "label": "" + "label": "Полный доступ" } } } }, "dangerZone": { - "title": "Зона опасности", + "title": "Опасная зона", "action": { "rename": { - "label": "", - "description": "", - "button": "", + "label": "Переименовать панель", + "description": "Изменение названия нарушит все существующие ссылки на эту панель.", + "button": "Изменить название", "modal": { - "title": "" + "title": "Переименовать панель" } }, "visibility": { - "label": "", + "label": "Изменить видимость панели", "description": { - "public": "", - "private": "" + "public": "Эта панель сейчас публичная.", + "private": "Эта панель сейчас приватная." }, "button": { - "public": "", - "private": "" + "public": "Сделать приватной", + "private": "Сделать публичной" }, "confirm": { "public": { - "title": "", - "description": "" + "title": "Сделать панель приватной", + "description": "Вы уверены, что хотите сделать эту панель приватной? Панель будет скрыта от публичного доступа. Ссылки для гостевых пользователей перестанут работать." }, "private": { - "title": "", - "description": "" + "title": "Сделать панель публичной", + "description": "Вы уверены, что хотите сделать эту панель публичной? Панель станет доступной для всех." } } }, "delete": { - "label": "", - "description": "", - "button": "", + "label": "Удалить эту панель", + "description": "После удаления панели восстановление будет невозможно. Пожалуйста, будьте уверены в своём решении.", + "button": "Удалить эту панель", "confirm": { "title": "Удалить панель", - "description": "" + "description": "Вы уверены, что хотите удалить эту панель? Действие навсегда удалит панель и всё её содержимое." } } } } } + }, + "error": { + "noBoard": { + "title": "Добро пожаловать в Homarr", + "description": "Современная панель управления для удобного доступа к вашим приложениям и сервисам.", + "link": "Создать первую панель", + "notice": "Чтобы убрать эту страницу, создайте панель и установите её как домашнюю" + }, + "notFound": { + "title": "Панель не найдена", + "description": "Указанная панель не найдена или у вас нет к ней доступа.", + "link": "Просмотр всех панелей", + "notice": "Проверьте ссылку или обратитесь к администратору, если считаете, что она должна быть доступна" + }, + "homeBoard": { + "title": "Нет домашней панели", + "admin": { + "description": "Домашняя панель для сервера ещё не установлена.", + "link": "Настроить общесерверную домашнюю панель", + "notice": "Чтобы убрать эту страницу для всех пользователей, установите домашнюю панель для сервера" + }, + "user": { + "description": "Вы ещё не установили домашнюю панель.", + "link": "Настроить вашу домашнюю панель", + "notice": "Чтобы убрать эту страницу, укажите домашнюю панель в настройках" + }, + "anonymous": { + "description": "Администратор сервера ещё не установил домашнюю панель.", + "link": "Просмотр публичных панелей", + "notice": "Чтобы убрать эту страницу, попросите администратора сервера установить домашнюю панель" + } + } } }, "management": { - "metaTitle": "", + "metaTitle": "Управление", "title": { - "morning": "", - "afternoon": "", - "evening": "" + "morning": "Доброе утро, {username}", + "afternoon": "Добрый день, {username}", + "evening": "Добрый вечер, {username}" }, "notFound": { - "title": "", - "text": "" + "title": "Не найдено", + "text": "Запрошенный ресурс не найден" }, "navbar": { "items": { "home": "Главная", "boards": "Панели", "apps": "Приложения", - "integrations": "", - "searchEngies": "", - "medias": "", + "integrations": "Интеграции", + "searchEngies": "Поисковые системы", + "medias": "Медиафайлы", "users": { "label": "Пользователи", "items": { "manage": "Управление", "invites": "Приглашения", - "groups": "" + "groups": "Группы" } }, "tools": { "label": "Инструменты", "items": { - "docker": "", - "logs": "", - "api": "", - "tasks": "" + "docker": "Docker", + "logs": "Логи", + "api": "API", + "certificates": "", + "tasks": "Задачи" } }, "settings": "Настройки", "help": { - "label": "Помощь", + "label": "Справка", "items": { "documentation": "Документация", - "submitIssue": "", + "submitIssue": "Сообщить о проблеме", "discord": "Сообщество Discord", - "sourceCode": "" + "sourceCode": "Исходный код" } }, "about": "О программе" @@ -1860,72 +2125,89 @@ "board": "Панели", "user": "Пользователи", "invite": "Приглашения", - "integration": "", + "integration": "Интеграции", "app": "Приложения", - "group": "" + "group": "Группы" }, "statisticLabel": { "boards": "Панели", - "resources": "", - "authentication": "", - "authorization": "" + "resources": "Ресурсы", + "authentication": "Аутентификация", + "authorization": "Авторизация" } }, "board": { "title": "Ваши панели", "action": { "new": { - "label": "" + "label": "Новая панель" }, "open": { - "label": "" + "label": "Открыть панель" }, "settings": { "label": "Настройки" }, "setHomeBoard": { - "label": "", + "label": "Сделать домашней панелью", "badge": { "label": "Главная", + "tooltip": "Эта панель будет показываться как ваша домашняя панель" + } + }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", "tooltip": "" } }, + "duplicate": { + "label": "" + }, "delete": { "label": "Удалить навсегда", "confirm": { - "title": "Удалить панель", - "description": "" + "title": "Удаление панели", + "description": "Вы уверены, что хотите удалить панель {name}?" } } }, "visibility": { - "public": "", - "private": "" + "public": "Эта панель публичная", + "private": "Эта панель приватная" }, "modal": { "createBoard": { "field": { "name": { - "label": "Имя" + "label": "Название" } } } } }, "media": { - "includeFromAllUsers": "" + "includeFromAllUsers": "Включая медиафайлы от всех пользователей" }, "user": { - "back": "", - "fieldsDisabledExternalProvider": "", + "back": "Вернуться к пользователям", + "fieldsDisabledExternalProvider": "Некоторые поля отключены, так как ими управляет внешняя система аутентификации.", "setting": { "general": { "title": "Общие", "item": { - "language": "", - "board": "", + "language": "Язык и регион", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Первый день недели", - "accessibility": "Доступность" + "accessibility": "Специальные возможности" } }, "security": { @@ -1936,63 +2218,63 @@ } }, "list": { - "metaTitle": "Управлять пользователями", + "metaTitle": "Управление пользователями", "title": "Пользователи" }, "edit": { - "metaTitle": "" + "metaTitle": "Редактирование пользователя {username}" }, "create": { - "metaTitle": "Создать пользователя", - "title": "", + "metaTitle": "Создание пользователя", + "title": "Создать нового пользователя", "step": { "personalInformation": { - "label": "" + "label": "Личные данные" }, "security": { "label": "Безопасность" }, "groups": { - "label": "", - "title": "", - "description": "" + "label": "Группы", + "title": "Выберите все группы, в которые должен входить пользователь", + "description": "Группа {everyoneGroup} назначается всем пользователям и не может быть удалена." }, "review": { - "label": "" + "label": "Проверка" }, "completed": { - "title": "" + "title": "Пользователь создан" }, "error": { - "title": "" + "title": "Не удалось создать пользователя" } }, "action": { - "createAnother": "", - "back": "" + "createAnother": "Создать ещё одного пользователя", + "back": "Вернуться к списку пользователей" } }, "invite": { - "title": "Управление приглашениями пользователей", + "title": "Управление приглашениями", "action": { "new": { - "title": "", - "description": "По истечении этого срока приглашение перестает быть действительным, и получатель приглашения не сможет создать аккаунт." + "title": "Новое приглашение", + "description": "После истечения срока действия приглашение станет недействительным, и получатель не сможет создать учётную запись." }, "copy": { - "title": "", - "description": "", - "link": "Ссылка на приглашение", - "button": "" + "title": "Копировать приглашение", + "description": "Приглашение сгенерировано. После закрытия этого окна вы больше не сможете скопировать эту ссылку. Если вы передумали приглашать пользователя, вы можете удалить это приглашение в любое время.", + "link": "Ссылка для приглашения", + "button": "Копировать и закрыть" }, "delete": { "title": "Удалить приглашение", - "description": "Вы уверены, что хотите удалить это приглашение? Пользователи, получившие эту ссылку, больше не смогут создать аккаунт по этой ссылке." + "description": "Вы уверены, что хотите удалить это приглашение? Пользователи с этой ссылкой больше не смогут создать учётную запись." } }, "field": { "id": { - "label": "" + "label": "ID" }, "creator": { "label": "Создатель" @@ -2007,23 +2289,23 @@ } }, "group": { - "back": "", + "back": "Вернуться к группам", "setting": { "general": { "title": "Общие", - "owner": "", - "ownerOfGroup": "", - "ownerOfGroupDeleted": "" + "owner": "Владелец", + "ownerOfGroup": "Владелец этой группы", + "ownerOfGroupDeleted": "Владелец этой группы был удалён. В данный момент у группы нет владельца." }, "members": { - "title": "", - "search": "", - "notFound": "" + "title": "Участники", + "search": "Найти участника", + "notFound": "Участники не найдены" }, "permissions": { - "title": "", + "title": "Разрешения", "form": { - "unsavedChanges": "" + "unsavedChanges": "У вас есть несохранённые изменения!" } } } @@ -2032,137 +2314,154 @@ "title": "Настройки", "notification": { "success": { - "message": "" + "message": "Настройки успешно сохранены" }, "error": { - "message": "" + "message": "Не удалось сохранить настройки" } }, "section": { "analytics": { - "title": "", + "title": "Аналитика", "general": { - "title": "", - "text": "" + "title": "Отправлять анонимную аналитику", + "text": "Homarr использует открытое программное обеспечение Umami для сбора обезличенных данных об использовании. Сбор данных никогда не включает личную информацию и полностью соответствует GDPR и CCPA. Мы рекомендуем включить аналитику, так как это помогает нашей команде выявлять проблемы и определять приоритеты в разработке." }, "widgetData": { - "title": "", - "text": "" + "title": "Данные о виджетах", + "text": "Отправлять информацию о настроенных виджетах (и их количестве). Не включает URL-адреса, названия или другие данные." }, "integrationData": { - "title": "", - "text": "" + "title": "Данные об интеграциях", + "text": "Отправлять информацию о настроенных интеграциях (и их количестве). Не включает URL-адреса, названия или другие данные." }, "usersData": { - "title": "", - "text": "" + "title": "Данные о пользователях", + "text": "Отправлять количество пользователей и информацию об использовании единого входа" } }, "crawlingAndIndexing": { - "title": "", - "warning": "", + "title": "Сканирование и индексация", + "warning": "Включение или отключение любых настроек здесь существенно повлияет на то, как поисковые системы будут индексировать и сканировать вашу страницу. Все настройки носят рекомендательный характер, и поисковые системы могут учитывать их по своему усмотрению. Изменения могут вступить в силу через несколько дней или недель. Некоторые настройки могут быть специфичны для конкретных поисковых систем.", "noIndex": { - "title": "", - "text": "" + "title": "Не индексировать", + "text": "Не индексировать сайт в поисковых системах и не показывать его в результатах поиска" }, "noFollow": { - "title": "", - "text": "" + "title": "Не следовать по ссылкам", + "text": "Не переходить по ссылкам при индексации. Отключение приведёт к тому, что поисковые роботы будут пытаться перейти по всем ссылкам в Homarr." }, "noTranslate": { - "title": "", - "text": "" + "title": "Не предлагать перевод", + "text": "Когда язык сайта отличается от предпочитаемого пользователем, Google будет показывать ссылку на перевод в результатах поиска" }, "noSiteLinksSearchBox": { - "title": "", - "text": "" + "title": "Не показывать поле поиска по сайту", + "text": "Google создаст поле поиска с найденными ссылками вместе с другими прямыми ссылками. Включение этой опции попросит Google отключить это поле." } }, "board": { - "title": "", + "title": "Панели", "homeBoard": { + "label": "Общая домашняя панель", + "mobileLabel": "", + "description": "Для выбора доступны только публичные панели" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Внешний вид", "defaultColorScheme": { - "label": "", + "label": "Цветовая схема по умолчанию", "options": { - "light": "", - "dark": "" + "light": "Светлая", + "dark": "Тёмная" } } }, "culture": { - "title": "", + "title": "Локализация", "defaultLocale": { - "label": "" + "label": "Язык по умолчанию" } } } }, "tool": { "tasks": { - "title": "", + "title": "Задачи", "status": { - "idle": "", - "running": "Работает", + "idle": "Ожидание", + "running": "Выполняется", "error": "Ошибка" }, "job": { - "iconsUpdater": { + "minecraftServerStatus": { "label": "" }, + "iconsUpdater": { + "label": "Обновление иконок" + }, "analytics": { - "label": "" + "label": "Аналитика" }, "smartHomeEntityState": { - "label": "" + "label": "Состояние объектов умного дома" }, "ping": { - "label": "" + "label": "Проверка доступности" }, "mediaServer": { "label": "Медиасервер" }, "mediaOrganizer": { - "label": "" + "label": "Организация медиафайлов" }, "downloads": { - "label": "" + "label": "Загрузки" }, "mediaRequestStats": { - "label": "" + "label": "Статистика запросов медиаконтента" }, "mediaRequestList": { - "label": "" + "label": "Список запросов медиаконтента" }, "rssFeeds": { - "label": "" + "label": "RSS-ленты" }, "indexerManager": { - "label": "" + "label": "Управление индексаторами" }, "healthMonitoring": { - "label": "" + "label": "Мониторинг состояния" }, "dnsHole": { - "label": "" + "label": "Данные DNS-фильтра" }, "sessionCleanup": { - "label": "" + "label": "Очистка сессий" + }, + "updateChecker": { + "label": "Проверка обновлений" + }, + "mediaTranscoding": { + "label": "Перекодирование медиафайлов" } } }, "api": { - "title": "", + "title": "API", "modal": { "createApiToken": { - "title": "", - "description": "", - "button": "" + "title": "API-токен создан", + "description": "API-токен создан. Этот токен зашифрован в базе данных и будет показан только один раз. После закрытия окна его нельзя будет восстановить.", + "button": "Копировать и закрыть" } }, "tab": { @@ -2170,15 +2469,15 @@ "label": "Документация" }, "apiKey": { - "label": "", - "title": "", + "label": "Аутентификация", + "title": "API-ключи", "button": { - "createApiToken": "" + "createApiToken": "Создать API-токен" }, "table": { "header": { - "id": "", - "createdBy": "" + "id": "ID", + "createdBy": "Создан пользователем" } } } @@ -2186,20 +2485,20 @@ } }, "about": { - "version": "", - "text": "", + "version": "Версия {version}", + "text": "Homarr — это проект с открытым исходным кодом, поддерживаемый сообществом и развиваемый добровольцами. Благодаря этим людям Homarr остаётся растущим проектом с 2021 года. Наша команда работает над Homarr полностью удалённо из разных стран в своё свободное время без какой-либо компенсации.", "accordion": { "contributors": { - "title": "", - "subtitle": "" + "title": "Участники проекта", + "subtitle": "{count} поддерживают код и Homarr" }, "translators": { - "title": "", - "subtitle": "" + "title": "Переводчики", + "subtitle": "{count} помогают с переводами на разные языки" }, "libraries": { - "title": "", - "subtitle": "" + "title": "Библиотеки", + "subtitle": "{count} используются в коде Homarr" } } } @@ -2208,24 +2507,24 @@ "docker": { "title": "Контейнеры", "table": { - "updated": "", - "search": "", - "selected": "" + "updated": "Обновлено {when}", + "search": "Поиск среди {count} контейнеров", + "selected": "Выбрано {selectCount} из {totalCount} контейнеров" }, "field": { "name": { - "label": "Имя" + "label": "Название" }, "state": { "label": "Состояние", "option": { "created": "Создан", "running": "Работает", - "paused": "Приостановлено", - "restarting": "Перезапуск", - "exited": "", - "removing": "Удаление", - "dead": "" + "paused": "Приостановлен", + "restarting": "Перезапускается", + "exited": "Остановлен", + "removing": "Удаляется", + "dead": "Нерабочий" } }, "containerImage": { @@ -2240,12 +2539,12 @@ "label": "Запустить", "notification": { "success": { - "title": "", - "message": "" + "title": "Контейнеры запущены", + "message": "Контейнеры успешно запущены" }, "error": { - "title": "", - "message": "" + "title": "Не удалось запустить контейнеры", + "message": "Не удалось запустить контейнеры" } } }, @@ -2253,12 +2552,12 @@ "label": "Остановить", "notification": { "success": { - "title": "", - "message": "" + "title": "Контейнеры остановлены", + "message": "Контейнеры успешно остановлены" }, "error": { - "title": "", - "message": "" + "title": "Не удалось остановить контейнеры", + "message": "Не удалось остановить контейнеры" } } }, @@ -2266,12 +2565,12 @@ "label": "Перезапустить", "notification": { "success": { - "title": "", - "message": "" + "title": "Контейнеры перезапущены", + "message": "Контейнеры успешно перезапущены" }, "error": { - "title": "", - "message": "" + "title": "Не удалось перезапустить контейнеры", + "message": "Не удалось перезапустить контейнеры" } } }, @@ -2279,16 +2578,29 @@ "label": "Удалить", "notification": { "success": { - "title": "", - "message": "" + "title": "Контейнеры удалены", + "message": "Контейнеры успешно удалены" }, "error": { - "title": "", - "message": "" + "title": "Не удалось удалить контейнеры", + "message": "Не удалось удалить контейнеры" } } }, "refresh": { + "label": "Обновить", + "notification": { + "success": { + "title": "Контейнеры обновлены", + "message": "Отображаются актуальные данные" + }, + "error": { + "title": "Не удалось обновить контейнеры", + "message": "Произошла ошибка при обновлении данных о контейнерах" + } + } + }, + "addToHomarr": { "label": "", "notification": { "success": { @@ -2299,37 +2611,43 @@ "title": "", "message": "" } + }, + "modal": { + "title": "" } } + }, + "error": { + "internalServerError": "Произошла ошибка при обновлении данных о контейнерах" } }, "permission": { - "title": "", + "title": "Права доступа", "userSelect": { - "title": "" + "title": "Добавить права для пользователя" }, "groupSelect": { - "title": "" + "title": "Добавить права для группы" }, "tab": { "user": "Пользователи", - "group": "", - "inherited": "" + "group": "Группы", + "inherited": "Унаследованные группы" }, "field": { "user": { "label": "Пользователь" }, "group": { - "label": "" + "label": "Группа" }, "permission": { - "label": "" + "label": "Права доступа" } }, "action": { - "saveUser": "", - "saveGroup": "" + "saveUser": "Сохранить права пользователя", + "saveGroup": "Сохранить права группы" } }, "navigationStructure": { @@ -2339,33 +2657,33 @@ "label": "Панели" }, "integrations": { - "label": "", + "label": "Интеграции", "edit": { - "label": "Изменить" + "label": "Редактировать" }, "new": { - "label": "" + "label": "Новая" } }, "search-engines": { - "label": "", + "label": "Поисковые системы", "new": { - "label": "" + "label": "Новая" }, "edit": { - "label": "Изменить" + "label": "Редактировать" } }, "medias": { - "label": "" + "label": "Медиафайлы" }, "apps": { "label": "Приложения", "new": { - "label": "" + "label": "Новое" }, "edit": { - "label": "Изменить" + "label": "Редактировать" } }, "users": { @@ -2377,7 +2695,7 @@ "security": "Безопасность", "board": "Панели", "groups": { - "label": "" + "label": "Группы" }, "invites": { "label": "Приглашения" @@ -2386,9 +2704,12 @@ "tools": { "label": "Инструменты", "docker": { - "label": "" + "label": "Docker" }, "logs": { + "label": "Логи" + }, + "certificates": { "label": "" } }, @@ -2401,28 +2722,28 @@ } }, "search": { - "placeholder": "", - "nothingFound": "", + "placeholder": "Найдётся все", + "nothingFound": "Ничего не найдено", "error": { - "fetch": "" + "fetch": "Произошла ошибка при получении данных" }, "mode": { "appIntegrationBoard": { - "help": "", + "help": "Поиск приложений, интеграций или панелей", "group": { "app": { "title": "Приложения", "children": { "action": { "open": { - "label": "" + "label": "Открыть URL приложения" }, "edit": { - "label": "" + "label": "Редактировать приложение" } }, "detail": { - "title": "" + "title": "Выберите действие для приложения" } } }, @@ -2431,114 +2752,122 @@ "children": { "action": { "open": { - "label": "" + "label": "Открыть панель" }, "homeBoard": { + "label": "Сделать домашней панелью" + }, + "mobileBoard": { "label": "" }, "settings": { - "label": "" + "label": "Открыть настройки" } }, "detail": { - "title": "" + "title": "Выберите действие для панели" } } }, "integration": { - "title": "" + "title": "Интеграции" } } }, "command": { - "help": "", + "help": "Активировать режим команд", "group": { "localCommand": { - "title": "" + "title": "Локальные команды" }, "globalCommand": { - "title": "", + "title": "Глобальные команды", "option": { "colorScheme": { - "light": "", - "dark": "" + "light": "Переключить на светлую тему", + "dark": "Переключить на тёмную тему" }, "language": { - "label": "", + "label": "Изменить язык", "children": { "detail": { - "title": "" + "title": "Выберите предпочитаемый язык" } } }, "newBoard": { - "label": "" + "label": "Создать новую панель" }, "importBoard": { - "label": "" + "label": "Импортировать панель" }, "newApp": { - "label": "" + "label": "Создать новое приложение" }, "newIntegration": { - "label": "", + "label": "Создать новую интеграцию", "children": { "detail": { - "title": "" + "title": "Выберите тип интеграции для создания" } } }, "newUser": { - "label": "" + "label": "Создать нового пользователя" }, "newInvite": { - "label": "" + "label": "Создать новое приглашение" }, "newGroup": { - "label": "" + "label": "Создать новую группу" } } } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { - "help": "", + "help": "Использовать внешнюю поисковую систему", "group": { "searchEngine": { - "title": "", + "title": "Поисковые системы", "children": { "action": { "search": { - "label": "" + "label": "Искать через {name}" } }, "detail": { - "title": "" + "title": "Выберите действие для поисковой системы" }, "searchResults": { - "title": "" + "title": "Выберите результат поиска для действий" } }, "option": { "google": { - "name": "", - "description": "" + "name": "Google", + "description": "Поиск в интернете через Google" }, "bing": { - "name": "", - "description": "" + "name": "Bing", + "description": "Поиск в интернете через Bing" }, "duckduckgo": { - "name": "", - "description": "" + "name": "DuckDuckGo", + "description": "Поиск в интернете через DuckDuckGo" }, "torrent": { "name": "Торренты", - "description": "" + "description": "Поиск торрентов на torrentdownloads.pro" }, "youTube": { - "name": "", - "description": "" + "name": "YouTube", + "description": "Поиск видео на YouTube" } } } @@ -2547,16 +2876,16 @@ "help": { "group": { "mode": { - "title": "" + "title": "Режимы" }, "help": { - "title": "Помощь", + "title": "Справка", "option": { "documentation": { "label": "Документация" }, "submitIssue": { - "label": "" + "label": "Сообщить о проблеме" }, "discord": { "label": "Сообщество Discord" @@ -2567,64 +2896,82 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { - "title": "" + "title": "Локальные результаты" } } }, "page": { - "help": "", + "help": "Поиск по страницам", "group": { "page": { - "title": "", + "title": "Страницы", "option": { "manageHome": { - "label": "" + "label": "Управление главной страницей" }, "manageBoard": { - "label": "" + "label": "Управление панелями" }, "manageApp": { - "label": "" + "label": "Управление приложениями" }, "manageIntegration": { - "label": "" + "label": "Управление интеграциями" }, "manageSearchEngine": { - "label": "" + "label": "Управление поисковыми системами" }, "manageMedia": { - "label": "" + "label": "Управление медиафайлами" }, "manageUser": { - "label": "Управлять пользователями" + "label": "Управление пользователями" }, "manageInvite": { - "label": "" + "label": "Управление приглашениями" }, "manageGroup": { - "label": "" + "label": "Управление группами" }, "manageDocker": { - "label": "" + "label": "Управление Docker" }, "manageApi": { - "label": "" + "label": "Swagger API" }, "manageLog": { - "label": "" + "label": "Просмотр логов" }, "manageTask": { - "label": "" + "label": "Управление задачами" }, "manageSettings": { - "label": "" + "label": "Глобальные настройки" }, "about": { "label": "О программе" }, "homeBoard": { - "label": "" + "label": "Домашняя панель" }, "preferences": { "label": "Ваши настройки" @@ -2634,37 +2981,37 @@ } }, "userGroup": { - "help": "", + "help": "Поиск пользователей или групп", "group": { "user": { "title": "Пользователи", "children": { "action": { "detail": { - "label": "" + "label": "Показать сведения о пользователе" } }, "detail": { - "title": "" + "title": "Выберите действие для пользователя" } } }, "group": { - "title": "", + "title": "Группы", "children": { "action": { "detail": { - "label": "" + "label": "Показать сведения о группе" }, "manageMember": { - "label": "" + "label": "Управление участниками" }, "managePermission": { - "label": "" + "label": "Управление разрешениями" } }, "detail": { - "title": "" + "title": "Выберите действие для группы" } } } @@ -2672,75 +3019,132 @@ } }, "engine": { - "search": "", + "search": "Найти поисковую систему", "field": { "name": { - "label": "Имя" + "label": "Название" }, "short": { - "label": "" + "label": "Краткое название" }, "urlTemplate": { - "label": "" + "label": "Шаблон URL поиска" }, "description": { - "label": "" + "label": "Описание" } }, "page": { "list": { - "title": "", + "title": "Поисковые системы", "noResults": { - "title": "", - "action": "" + "title": "Поисковые системы пока отсутствуют", + "action": "Создать первую поисковую систему" }, - "interactive": "" + "interactive": "Интерактивная, использует интеграцию" }, "create": { - "title": "", + "title": "Новая поисковая система", "notification": { "success": { - "title": "", - "message": "" + "title": "Поисковая система создана", + "message": "Поисковая система успешно создана" }, "error": { - "title": "", - "message": "" + "title": "Не удалось создать", + "message": "Не удалось создать поисковую систему" } } }, "edit": { - "title": "", + "title": "Редактирование поисковой системы", "notification": { "success": { - "title": "", - "message": "" + "title": "Изменения сохранены", + "message": "Поисковая система успешно сохранена" }, "error": { - "title": "", - "message": "" + "title": "Не удалось сохранить", + "message": "Не удалось сохранить поисковую систему" } }, - "configControl": "", + "configControl": "Настройка", "searchEngineType": { - "generic": "", - "fromIntegration": "" + "generic": "Обычная", + "fromIntegration": "Из интеграции" } }, "delete": { - "title": "", - "message": "", + "title": "Удаление поисковой системы", + "message": "Вы уверены, что хотите удалить поисковую систему '{name}'?", "notification": { "success": { - "title": "", - "message": "" + "title": "Поисковая система удалена", + "message": "Поисковая система успешно удалена" }, "error": { - "title": "", - "message": "" + "title": "Не удалось удалить", + "message": "Не удалось удалить поисковую систему" } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/sk.json b/packages/translation/src/lang/sk.json index 0b0db98ac..bfd72dbdf 100644 --- a/packages/translation/src/lang/sk.json +++ b/packages/translation/src/lang/sk.json @@ -1,26 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "Víta Vás Homár", + "subtitle": "Začnime s nastavením inštancie Homár.", + "description": "Ak chcete začať, vyberte, ako chcete nastaviť inštanciu Homár.", + "action": { + "scratch": "Začať odznova", + "importOldmarr": "Import z Homarr pred 1.0" + } + }, + "import": { + "title": "Importovať dáta", + "subtitle": "Údaje môžete importovať z existujúcej inštancie aplikácie Homarr.", + "dropzone": { + "title": "Potiahnite súbor ZIP sem alebo kliknite na tlačidlo prehľadávania", + "description": "Nahraný súbor zip sa spracuje a vy si budete môcť vybrať, čo chcete importovať." + }, + "fileInfo": { + "action": { + "change": "Zmeniť súbor" + } + }, + "importSettings": { + "title": "Import nastavení", + "description": "Nakonfigurujte správanie importu" + }, + "boardSelection": { + "title": "Nájdených {count} dosiek", + "description": "Vyberte všetky dosky s veľkosťou, ktorú chcete importovať", + "action": { + "selectAll": "Vybrať všetko", + "unselectAll": "Zrušiť výber" + } + }, + "summary": { + "title": "Súhrn importu", + "description": "V nasledujúcom prehľade môžete vidieť, čo sa bude importovať", + "action": { + "import": "Potvrďte import a pokračujte" + }, + "entities": { + "apps": "Aplikácie", + "boards": "Dosky", + "integrations": "Integrácie", + "credentialUsers": "Používatelia poverení" + } + }, + "tokenModal": { + "title": "Zadajte token importu", + "field": { + "token": { + "label": "Token", + "description": "Zadajte zobrazený token importu z predchádzajúcej inštancie homarr" + } + }, + "notification": { + "error": { + "title": "Neplatný token", + "message": "Zadaný token je neplatný" + } + } + } + }, + "user": { + "title": "Používateľ administrátora", + "subtitle": "Zadajte poverenia pre používateľa správcu.", + "notification": { + "success": { + "title": "Používateľ vytvorený", + "message": "Používateľ bol úspešne vytvorený" + }, + "error": { + "title": "Vytvorenie užívateľa zlyhalo" + } + } + }, + "group": { + "title": "Externá skupina", + "subtitle": "Zadajte skupinu, ktorá sa má použiť pre externých používateľov.", + "form": { + "name": { + "label": "Názov skupiny", + "description": "Názov sa musí zhodovať s administrátorskou skupinou externého poskytovateľa" + } + } + }, + "settings": { + "title": "Nastavenia", + "subtitle": "Nakonfigurujte nastavenia servera." + }, + "finish": { + "title": "Dokončiť nastavenie", + "subtitle": "Ste pripravení vyraziť!", + "description": "Úspešne ste dokončili proces nastavenia. Teraz môžete začať používať Homarr. Vyberte ďalšiu akciu:", + "action": { + "goToBoard": "Prejdite na nástenku {name}", + "createBoard": "Vytvorte si svoju prvú nástenku", + "inviteUser": "Pozvite ďalších používateľov", + "docs": "Prečítajte si dokumentáciu" + } + } + }, + "backToStart": "Späť na začiatok" + }, "user": { "title": "Používatelia", "name": "Používateľ", "page": { "login": { - "title": "", - "subtitle": "" + "title": "Prihláste sa do vášho účtu.", + "subtitle": "Vitajte späť! Zadajte svoje poverenia" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "Pridajte sa k Homarrovi", + "subtitle": "Vítajte v Homarr! Prosím, vytvorte si účet", + "description": "Pozval vás {username}" }, "init": { - "title": "", - "subtitle": "" + "title": "Nová inštalácia Homarr", + "subtitle": "Vytvorte počiatočného administrátora" } }, "field": { "email": { "label": "E-mail", - "verified": "" + "verified": "Overený" }, "username": { "label": "Používateľské meno" @@ -28,46 +133,46 @@ "password": { "label": "Heslo", "requirement": { - "length": "", + "length": "Obsahuje aspoň 8 znakov", "lowercase": "Zahŕňa malé písmeno", "uppercase": "Zahŕňa veľké písmená", "number": "Vrátane čísiel", - "special": "" + "special": "Obsahuje špeciálny symbol" } }, "passwordConfirm": { "label": "Potvrdenie hesla" }, "previousPassword": { - "label": "" + "label": "Predchádzajúce heslo" }, "homeBoard": { - "label": "" + "label": "Domáca doska" }, "pingIconsEnabled": { - "label": "" + "label": "Používanie ikon pre pingy" } }, "error": { - "usernameTaken": "" + "usernameTaken": "Používateľské meno je už obsadené" }, "action": { "login": { "label": "Prihlásiť sa", - "labelWith": "", + "labelWith": "Prihlásiť sa cez {provider}", "notification": { "success": { - "title": "", - "message": "" + "title": "Prihlásenie bolo úspešné", + "message": "Ste prihlásený" }, "error": { - "title": "", - "message": "" + "title": "Prihlásenie zlyhalo", + "message": "Vaše prihlásenie zlyhalo" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "Zabudli ste heslo?", + "description": "Správca môže použiť nasledujúci príkaz na obnovenie hesla:" } }, "register": { @@ -75,81 +180,91 @@ "notification": { "success": { "title": "Účet bol Vytvorený", - "message": "" + "message": "Prosím, prihláste sa, ak chcete pokračovať" }, "error": { - "title": "", - "message": "" + "title": "Vytvorenie účtu zlyhalo", + "message": "Váš účet sa nepodarilo vytvoriť" } } }, "create": "Vytvoriť užívateľa", "changePassword": { - "label": "", + "label": "Zmeniť heslo", "notification": { "success": { - "message": "" + "message": "Heslo bolo úspešne zmenené" }, "error": { - "message": "" + "message": "Nepodarilo sa zmeniť heslo" } } }, "changeHomeBoard": { "notification": { "success": { - "message": "" + "message": "Domovská doska sa úspešne zmenila" }, "error": { - "message": "" + "message": "Nie je možné zmeniť domovskú dosku" + } + } + }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "Predvolený vyhľadávací nástroj sa úspešne zmenil" + }, + "error": { + "message": "Nie je možné zmeniť predvolený vyhľadávací nástroj" } } }, "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "Prvý deň v týždni sa úspešne zmenil" }, "error": { - "message": "" + "message": "Nemožnosť zmeniť prvý deň v týždni" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "Ikony Ping boli úspešne prepnuté" }, "error": { - "message": "" + "message": "Nemožno prepínať ikony ping" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Zmeniť obrázok", "notification": { "success": { - "message": "" + "message": "Obrázok sa úspešne zmenil" }, "error": { - "message": "" + "message": "Nie je možné zmeniť obrázok" }, "toLarge": { - "title": "", - "message": "" + "title": "Obrázok je príliš veľký", + "message": "Maximálna veľkosť obrázka je {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Odstrániť obrázok", + "confirm": "Naozaj chcete odstrániť obrázok?", "notification": { "success": { - "message": "" + "message": "Obrázok úspešne odstránený" }, "error": { - "message": "" + "message": "Obrázok sa nedá odstrániť" } } } @@ -157,63 +272,63 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "Profil bol úspešne aktualizovaný" }, "error": { - "message": "" + "message": "Nepodarilo sa aktualizovať profil" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "Zmazať užívateľa natrvalo", + "description": "Odstráni tohto používateľa vrátane jeho preferencií. Neodstráni žiadne nástenky. Používateľ nebude upozornený.", + "confirm": "Ste si istý, že chcete vymazať používateľa {username} s jeho preferenciami?" }, "select": { - "label": "", - "notFound": "" + "label": "Vyberte používateľa", + "notFound": "Nenašiel sa žiadny používateľ" }, "transfer": { - "label": "" + "label": "Vyberte nového vlastníka" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "Skupiny", + "name": "Skupiny", + "search": "Vyhľadať skupinu", "field": { "name": "Názov", - "members": "" + "members": "Členovia" }, "permission": { "admin": { "title": "Správca", "item": { "admin": { - "label": "", - "description": "" + "label": "Administrátor", + "description": "Členovia s týmto povolením majú úplný prístup ku všetkým funkciám a nastaveniam" } } }, "app": { - "title": "", + "title": "Aplikácie", "item": { "create": { - "label": "", - "description": "" + "label": "Vytváranie aplikácií", + "description": "Umožniť členom vytvárať aplikácie" }, "use-all": { - "label": "", - "description": "" + "label": "Použi všetky aplikácie", + "description": "Umožniť členom pridávať akékoľvek aplikácie na svoje nástenky" }, "modify-all": { - "label": "", - "description": "" + "label": "Úprava všetkých aplikácií", + "description": "Povoliť členom upravovať všetky aplikácie" }, "full-all": { - "label": "", - "description": "" + "label": "Úplný prístup k aplikácii", + "description": "Povoliť členom spravovať, používať a odstraňovať ľubovoľnú aplikáciu" } } }, @@ -221,214 +336,215 @@ "title": "Dosky", "item": { "create": { - "label": "", - "description": "" + "label": "Vytvoriť tabule", + "description": "Povoliť členom vytvárať nástenky" }, "view-all": { - "label": "", - "description": "" + "label": "Zobraziť všetky dosky", + "description": "Povoliť členom vytvárať nástenky" }, "modify-all": { - "label": "", - "description": "" + "label": "Úprava všetkých dosiek", + "description": "Povoliť členom upravovať všetky nástenky (Nezahŕňa kontrolu prístupu a nebezpečnú zónu)" }, "full-all": { - "label": "", - "description": "" + "label": "Úplný prístup k doskám", + "description": "Povoliť členom zobrazovať, upravovať a odstraňovať všetky nástenky (vrátane kontroly prístupu a nebezpečnej zóny)" } } }, "integration": { - "title": "", + "title": "Integrácie", "item": { "create": { - "label": "", - "description": "" + "label": "Vytvoriť integrácie", + "description": "Umožnite členom vytvárať integrácie" }, "use-all": { - "label": "", - "description": "" + "label": "Použite všetky integrácie", + "description": "Umožňuje členom pridať akékoľvek integrácie na ich nástenky" }, "interact-all": { - "label": "", - "description": "" + "label": "Interakcia s akoukoľvek integráciou", + "description": "Umožnite členom interagovať s akoukoľvek integráciou" }, "full-all": { - "label": "", - "description": "" + "label": "Úplný prístup k integrácii", + "description": "Umožnite členom interagovať s akoukoľvek integráciou" } } }, "media": { - "title": "", + "title": "Médiá", "item": { "upload": { - "label": "", - "description": "" + "label": "Nahrajte médiá", + "description": "Umožniť členom nahrávať médiá" }, "view-all": { - "label": "", - "description": "" + "label": "Zobraziť všetky médiá", + "description": "Povoliť členom zobraziť všetky médiá" }, "full-all": { - "label": "", - "description": "" + "label": "Úplný prístup k médiám", + "description": "Umožnite členom spravovať a odstraňovať akékoľvek médiá" } } }, "other": { - "title": "", + "title": "Iné", "item": { "view-logs": { - "label": "", - "description": "" + "label": "Zobraziť denníky", + "description": "Povoliť členom zobraziť denníky" } } }, "search-engine": { - "title": "", + "title": "Vyhľadávače", "item": { "create": { - "label": "", - "description": "" + "label": "Vytvorte vyhľadávače", + "description": "Umožnite členom vytvárať vyhľadávače" }, "modify-all": { - "label": "", - "description": "" + "label": "Úprava všetkých vyhľadávačov", + "description": "Povoliť členom upravovať všetky vyhľadávacie nástroje" }, "full-all": { - "label": "", - "description": "" + "label": "Úplný prístup k vyhľadávaču", + "description": "Umožnite členom spravovať a odstraňovať akýkoľvek vyhľadávací nástroj" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "Niektorí členovia sú od externých poskytovateľov a nemožno ich tu spravovať", + "external": "Všetci členovia sú od externých poskytovateľov a nemožno ich tu spravovať" }, "reservedNotice": { - "message": "" + "message": "Táto skupina je vyhradená pre systémové použitie a obmedzuje niektoré akcie. " }, "action": { "create": { - "label": "", + "label": "Nová skupina", "notification": { "success": { - "message": "" + "message": "Skupina bola úspešne vytvorená" }, "error": { - "message": "" + "message": "Skupinu sa nepodarilo vytvoriť" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "Previesť vlastníctvo", + "description": "Preneste vlastníctvo tejto skupiny na iného používateľa.", + "confirm": "Naozaj chcete previesť vlastníctvo skupiny {name} na {username}?", "notification": { "success": { - "message": "" + "message": "Skupina {group} bola úspešne prevedená na {user}" }, "error": { - "message": "" + "message": "Nie je možné previesť vlastníctvo" } } }, "addMember": { - "label": "" + "label": "Pridať člena" }, "removeMember": { - "label": "", - "confirm": "" + "label": "Odstrániť člena", + "confirm": "Naozaj chcete odstrániť {user} z tejto skupiny?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "Odstrániť skupinu", + "description": "Po odstránení skupiny už niet cesty späť. Buďte si istí.", + "confirm": "Naozaj chcete odstrániť skupinu {name}?", "notification": { "success": { - "message": "" + "message": "Skupina {name} bola úspešne odstránená" }, "error": { - "message": "" + "message": "Nie je možné odstrániť skupinu {name}" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "Povolenia boli uložené", + "message": "Povolenia boli úspešne uložené" }, "error": { - "title": "", - "message": "" + "title": "Povolenia nie sú uložené", + "message": "Povolenia neboli uložené" } } }, "update": { "notification": { "success": { - "message": "" + "message": "Skupina {name} bola úspešne uložená" }, "error": { - "message": "" + "message": "Nie je možné uložiť skupinu {name}" } } }, "select": { - "label": "", - "notFound": "" + "label": "Vybrať skupinu", + "notFound": "Nenašla sa žiadna skupina" } } }, "app": { + "search": "Vyhľadať aplikáciu", "page": { "list": { "title": "Aplikácie", "noResults": { - "title": "", - "action": "" + "title": "Zatiaľ tu nie sú žiadne aplikácie", + "action": "Vytvorte svoju prvú aplikáciu" } }, "create": { - "title": "", + "title": "Nová aplikácia", "notification": { "success": { - "title": "", - "message": "" + "title": "Vytvorenie bolo úspešné", + "message": "Aplikácia bola úspešne vytvorená" }, "error": { - "title": "", - "message": "" + "title": "Vytvorenie zlyhalo", + "message": "Aplikáciu nebolo možné vytvoriť" } } }, "edit": { - "title": "", + "title": "Upraviť aplikáciu", "notification": { "success": { - "title": "", - "message": "" + "title": "Zmeny boli úspešne použité", + "message": "Aplikácia bola úspešne uložená" }, "error": { - "title": "", - "message": "" + "title": "Nie je možné použiť zmeny", + "message": "Aplikáciu sa nepodarilo uložiť" } } }, "delete": { - "title": "", - "message": "", + "title": "Odstrániť aplikáciu", + "message": "Naozaj chcete odstrániť aplikáciu {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "Úspešne zmazané", + "message": "Aplikácia bola úspešne odstránená" }, "error": { - "title": "", - "message": "" + "title": "Odstránenie zlyhalo", + "message": "Aplikáciu nie je možné odstrániť" } } } @@ -438,65 +554,65 @@ "label": "Názov" }, "description": { - "label": "" + "label": "Popis" }, "url": { - "label": "" + "label": "Url" } }, "action": { "select": { - "label": "", - "notFound": "" + "label": "Vybrať aplikáciu", + "notFound": "Nenašla sa žiadna aplikácia" } } }, "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "Integrácie", + "search": "Vyhľadať integrácie", "noResults": { - "title": "" + "title": "Zatiaľ neexistujú žiadne integrácie" } }, "create": { - "title": "", + "title": "Nová integrácia {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "Vytvorenie bolo úspešné", + "message": "Integrácia bola úspešne vytvorená" }, "error": { - "title": "", - "message": "" + "title": "Vytvorenie zlyhalo", + "message": "Integráciu nebolo možné vytvoriť" } } }, "edit": { - "title": "", + "title": "Úprava integrácie {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "Zmeny boli úspešne použité", + "message": "Integrácia bola úspešne uložená" }, "error": { - "title": "", - "message": "" + "title": "Nie je možné použiť zmeny", + "message": "Integráciu sa nepodarilo uložiť" } } }, "delete": { - "title": "", - "message": "", + "title": "Odstrániť integráciu", + "message": "Naozaj chcete odstrániť integráciu {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "Úspešne zmazané", + "message": "Integrácia bola úspešne odstránená" }, "error": { - "title": "", - "message": "" + "title": "Odstránenie zlyhalo", + "message": "Integráciu nie je možné odstrániť" } } } @@ -506,105 +622,113 @@ "label": "Názov" }, "url": { - "label": "" + "label": "Url" + }, + "attemptSearchEngineCreation": { + "label": "Vytvorte vyhľadávače", + "description": "Integrácia \"{kind}\" môže byť použitá s vyhľadávačmi. Toto začiarknite, ak chcete automaticky nakonfigurovať vyhľadávací nástroj." } }, "action": { - "create": "" + "create": "Nová integrácia" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "Otestujte pripojenie a vytvorte", + "edit": "Otestujte pripojenie a uložte" }, - "alertNotice": "", + "alertNotice": "Tlačidlo Uložiť sa aktivuje po úspešnom nadviazaní spojenia.", "notification": { "success": { - "title": "", - "message": "" + "title": "Pripojenie bolo úspešné!", + "message": "Spojenie bolo úspešne nadviazané" }, "invalidUrl": { "title": "Neplatná URL", - "message": "" + "message": "Adresa URL je neplatná" }, "secretNotDefined": { - "title": "", - "message": "" + "title": "Chýbajúce poverenia", + "message": "Neboli poskytnuté všetky poverenia" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "Neplatné prihlasovacie údaje", + "message": "Poverenia sú neplatné" }, "commonError": { - "title": "", - "message": "" + "title": "Zlyhalo pripojenie", + "message": "Spojenie sa nepodarilo nadviazať." }, "badRequest": { - "title": "", - "message": "" + "title": "Nesprávna požiadavka.", + "message": "Požiadavka mala nesprávny formát" }, "unauthorized": { - "title": "", - "message": "" + "title": "Neoprávnené", + "message": "Pravdepodobne nesprávne poverenia" }, "forbidden": { - "title": "", - "message": "" + "title": "Zakázané", + "message": "Pravdepodobne chýbajú povolenia" }, "notFound": { - "title": "", - "message": "" + "title": "Nenájdené", + "message": "Pravdepodobne nesprávna adresa URL alebo cesta" }, "internalServerError": { - "title": "", - "message": "" + "title": "Interná chyba servera", + "message": "Na serveri sa vyskytla chyba" }, "serviceUnavailable": { - "title": "", - "message": "" + "title": "Služba nie je k dispozícií", + "message": "Server je momentálne nedostupný" }, "connectionAborted": { - "title": "", - "message": "" + "title": "Pripojenie prerušené", + "message": "Spojenie bolo prerušené" }, "domainNotFound": { - "title": "", - "message": "" + "title": "Doména nenájdená", + "message": "Doménu sa nepodarilo nájsť" }, "connectionRefused": { - "title": "", - "message": "" + "title": "Pripojenie prerušené", + "message": "Pripojenie bolo zamietnuté." }, "invalidJson": { - "title": "", - "message": "" + "title": "Neplatný JSON", + "message": "Odpoveď nebola platná JSON" }, "wrongPath": { - "title": "", - "message": "" + "title": "Nesprávna cesta", + "message": "Cesta pravdepodobne nie je správna" } } }, "secrets": { - "title": "", - "lastUpdated": "", - "secureNotice": "", + "title": "Tajomstvá", + "lastUpdated": "Posledná aktualizácia {date}", + "notSet": { + "label": "Žiadna nastavená hodnota", + "tooltip": "Toto požadované tajomstvo ešte nebolo nastavené" + }, + "secureNotice": "Toto tajomstvo sa po vytvorení nedá obnoviť", "reset": { - "title": "", - "message": "" + "title": "Obnoviť tajomstvo", + "message": "Naozaj chcete obnoviť toto tajomstvo?" }, "noSecretsRequired": { - "segmentTitle": "", - "text": "" + "segmentTitle": "Žiadne tajomstvá", + "text": "Pre túto integráciu nie sú potrebné žiadne tajomstvá" }, "kind": { "username": { "label": "Používateľské meno", - "newLabel": "" + "newLabel": "Nové používateľské meno" }, "apiKey": { - "label": "", - "newLabel": "" + "label": "API kľúč", + "newLabel": "Nový API kľúč" }, "password": { "label": "Heslo", @@ -613,14 +737,14 @@ } }, "permission": { - "use": "", - "interact": "", - "full": "" + "use": "Vyberte integrácie v položkách", + "interact": "Interakcia s integráciami", + "full": "Úplný prístup k integrácii" } }, "media": { - "plural": "", - "search": "", + "plural": "Médiá", + "search": "Nájsť médiá", "field": { "name": "Názov", "size": "Veľkosť", @@ -628,129 +752,137 @@ }, "action": { "upload": { - "label": "", - "file": "", + "label": "Nahrajte médiá", + "file": "Vybrať súbor", "notification": { "success": { - "message": "" + "message": "Médium bolo úspešne odovzdané" }, "error": { - "message": "" + "message": "Médiá sa nepodarilo nahrať" } } }, "delete": { - "label": "", - "description": "", + "label": "Odstrániť médiá", + "description": "Ste si istí, že chcete odstrániť médiá ?", "notification": { "success": { - "message": "" + "message": "Médium bolo úspešne odstránené" }, "error": { - "message": "" + "message": "Médium nebolo možné vymazať" } } }, "copy": { - "label": "" + "label": "Skopírovať URL" } } }, "common": { - "beta": "", + "beta": "Beta", "error": "Chyba", "action": { "add": "Pridať", "apply": "Použiť", - "backToOverview": "", + "backToOverview": "Späť na prehľad", "create": "Vytvoriť", "edit": "Upraviť", - "import": "", + "import": "Importovať", "insert": "Vložiť", "remove": "Odstrániť", "save": "Uložiť", "saveChanges": "Uložiť zmeny", "cancel": "Zrušiť", "delete": "Vymazať", - "discard": "", + "discard": "Zahodiť", "confirm": "Potvrďte", - "continue": "", + "continue": "Pokračovať", "previous": "Predchádzajúci", "next": "Ďalej", - "checkoutDocs": "", + "checkoutDocs": "Pozrite si dokumentáciu", + "checkLogs": "Ďalšie podrobnosti nájdete v protokoloch", "tryAgain": "Skúste znova", - "loading": "" + "loading": "Nahrávam" }, - "here": "", + "here": "tu", "iconPicker": { - "label": "", - "header": "" + "label": "URL ikony", + "header": "Zadajte názov alebo objekty na filtrovanie ikon... Homarr pre vás vyhľadá ikony na stránke {countIcons} ." + }, + "colorScheme": { + "options": { + "light": "Svetlý", + "dark": "Tmavý" + } }, "information": { - "min": "", - "max": "", - "days": "", + "min": "Min", + "max": "Max", + "days": "Dni", "hours": "Hodiny", "minutes": "Minúty" }, "notification": { "create": { - "success": "", - "error": "" + "success": "Vytvorenie bolo úspešné", + "error": "Vytvorenie zlyhalo" }, "delete": { - "success": "", - "error": "" + "success": "Úspešne zmazané", + "error": "Odstránenie zlyhalo" }, "update": { - "success": "", - "error": "" + "success": "Zmeny boli úspešne použité", + "error": "Nie je možné použiť zmeny" }, "transfer": { - "success": "", - "error": "" + "success": "Úspešný transfer", + "error": "Prenos zlyhal" } }, "multiSelect": { - "placeholder": "" + "placeholder": "Vyberte jednu alebo viac hodnôt" }, "multiText": { - "placeholder": "", - "addLabel": "" + "placeholder": "Pridajte ďalšie hodnoty", + "addLabel": "Pridajte {value}" }, "select": { - "placeholder": "", + "placeholder": "Vyberte hodnotu", "badge": { - "recommended": "" + "recommended": "Odporúčané" } }, "userAvatar": { "menu": { - "switchToDarkMode": "", - "switchToLightMode": "", - "management": "", + "switchToDarkMode": "Prepnúť na tmavý motív", + "switchToLightMode": "Prepnúť na svetlý motív", + "management": "Administrácia", "preferences": "Vaše preferencie", - "logout": "", + "logout": "Odhlásiť", "login": "Prihlásiť sa", - "homeBoard": "", - "loggedOut": "" + "homeBoard": "Vaša domovská nástenka", + "loggedOut": "Odhlásený", + "updateAvailable": "{countUpdates} dostupné aktualizácie: {tag}" } }, "dangerZone": "Nebezpečná zóna", "noResults": "Nenašli sa žiadne výsledky", "preview": { - "show": "", - "hide": "" + "show": "Zobraziť náhľad", + "hide": "Skryť náhľad" }, "zod": { "errors": { "default": "Toto pole je neplatné", "required": "Toto pole je povinné", "string": { - "startsWith": "Toto pole musí začínať na {startsWith}", - "endsWith": "Toto pole musí končiť na {endsWith}", + "startsWith": "Toto pole musí začínať {startsWith}", + "endsWith": "Toto pole musí končiť {endsWith}", "includes": "Toto pole musí obsahovať {includes}", - "invalidEmail": "" + "invalidEmail": "Toto pole musí byť platný e-mail" }, "tooSmall": { "string": "Toto pole musí byť dlhé aspoň {minimum} znakov", @@ -761,12 +893,14 @@ "number": "Toto pole musí byť menšie alebo rovné {maximum}" }, "custom": { - "passwordsDoNotMatch": "", - "passwordRequirements": "", - "boardAlreadyExists": "", - "invalidFileType": "", - "fileTooLarge": "", - "invalidConfiguration": "" + "passwordsDoNotMatch": "Heslá sa nezhodujú", + "passwordRequirements": "Heslo nespĺňa požiadavky", + "boardAlreadyExists": "Doska s týmto názvom už existuje", + "invalidFileType": "Neplatný typ súboru, očakáva sa {expected}", + "invalidFileName": "", + "fileTooLarge": "Súbor je príliš veľký, maximálna veľkosť je {maxSize}", + "invalidConfiguration": "Neplatná konfigurácia", + "groupNameTaken": "Názov skupiny je už obsadený" } } } @@ -774,12 +908,12 @@ "section": { "dynamic": { "action": { - "create": "", - "remove": "" + "create": "Nová dynamická sekcia", + "remove": "Nová dynamická sekcia" }, "remove": { - "title": "", - "message": "" + "title": "Nová dynamická sekcia", + "message": "Naozaj chcete odstrániť túto dynamickú sekciu? Položky sa presunú na rovnaké miesto v nadradenej sekcii." } }, "category": { @@ -789,29 +923,29 @@ } }, "action": { - "create": "", - "edit": "", - "remove": "", + "create": "Nová kategória", + "edit": "Premenovať kategóriu", + "remove": "Odstrániť kategóriu", "moveUp": "Posunúť nahor", "moveDown": "Posunúť nadol", - "createAbove": "", - "createBelow": "" + "createAbove": "Nová kategória vyššie", + "createBelow": "Nová kategória nižšie" }, "create": { - "title": "", - "submit": "" + "title": "Nová kategória", + "submit": "Pridať kategóriu" }, "remove": { - "title": "", - "message": "" + "title": "Odstrániť kategóriu", + "message": "Naozaj chcete odstrániť kategóriu {name}?" }, "edit": { - "title": "", - "submit": "" + "title": "Premenovať kategóriu", + "submit": "Premenovať kategóriu" }, "menu": { "label": { - "create": "", + "create": "Nová kategória", "changePosition": "Zmeniť pozíciu" } } @@ -819,12 +953,12 @@ }, "item": { "action": { - "create": "", - "import": "", - "edit": "", - "moveResize": "", - "duplicate": "", - "remove": "" + "create": "Nová položka", + "import": "Importovať položku", + "edit": "Upraviť položku", + "moveResize": "Presunúť / zmeniť veľkosť položky", + "duplicate": "Duplikovať položku", + "remove": "Odstrániť položku" }, "menu": { "label": { @@ -832,11 +966,12 @@ } }, "create": { - "title": "", - "addToBoard": "" + "title": "Vyberte položku, ktorú chcete pridať", + "search": "Filtrovať položky", + "addToBoard": "Pridať na dosku" }, "moveResize": { - "title": "", + "title": "Presunúť / zmeniť veľkosť položky", "field": { "width": { "label": "Šírka" @@ -845,91 +980,91 @@ "label": "Výška" }, "xOffset": { - "label": "" + "label": "X offset" }, "yOffset": { - "label": "" + "label": "Y offset" } } }, "edit": { - "title": "", + "title": "Upraviť položku", "advancedOptions": { - "label": "", - "title": "" + "label": "Pokročilé možnosti", + "title": "Rozšírené možnosti položiek" }, "field": { "integrations": { - "label": "" + "label": "Integrácie" }, "customCssClasses": { - "label": "" + "label": "Vlastné css triedy" } } }, "remove": { - "title": "", - "message": "" + "title": "Odstrániť položku", + "message": "Naozaj chcete odstrániť túto položku?" } }, "widget": { "app": { - "name": "", - "description": "", + "name": "Aplikácia", + "description": "Vloží aplikáciu do tabule.", "option": { "appId": { - "label": "" + "label": "Vybrať aplikáciu" }, "openInNewTab": { "label": "Otvoriť na novej karte" }, "showTitle": { - "label": "" + "label": "Zobraziť názov aplikácie" }, "showDescriptionTooltip": { - "label": "" + "label": "Zobrazenie nápovedy k popisu" }, "pingEnabled": { - "label": "" + "label": "Povoliť jednoduchý ping" } }, "error": { "notFound": { - "label": "", - "tooltip": "" + "label": "Žiadna aplikácia", + "tooltip": "Nevybrali ste žiadnu platnú aplikáciu" } } }, "bookmarks": { - "name": "", - "description": "", + "name": "Záložky", + "description": "Zobrazuje viacero odkazov na aplikácie", "option": { "title": { - "label": "" + "label": "Názov" }, "layout": { - "label": "", + "label": "Rozloženie", "option": { "row": { - "label": "" + "label": "Horizontálne" }, "column": { - "label": "" + "label": "Vertikálne" }, "grid": { - "label": "" + "label": "Mriežka" } } }, "items": { - "label": "", - "add": "" + "label": "Záložky", + "add": "Pridať záložku" } } }, "dnsHoleSummary": { - "name": "", - "description": "", + "name": "Zhrnutie dier DNS", + "description": "Zobrazí súhrn vašej diery DNS", "option": { "layout": { "label": "Rozloženie", @@ -941,27 +1076,28 @@ "label": "Vertikálne" }, "grid": { - "label": "" + "label": "Mriežka" } } }, "usePiHoleColors": { - "label": "" + "label": "Použite farby Pi-Hole" } }, "error": { - "internalServerError": "", - "integrationsDisconnected": "" + "internalServerError": "Nepodarilo sa načítať súhrn dier DNS", + "integrationsDisconnected": "Nie sú dostupné žiadne údaje, všetky integrácie sú odpojené" }, "data": { "adsBlockedToday": "Zablokované dnes", "adsBlockedTodayPercentage": "Zablokované dnes", "dnsQueriesToday": "Poziadavky dnes", - "domainsBeingBlocked": "" - } + "domainsBeingBlocked": "Domény na adlistoch" + }, + "domainsTooltip": "Kvôli viacerým integráciám nemôže Homarr vypočítať presný počet blokovaných domén" }, "dnsHoleControls": { - "name": "", + "name": "Kontrola diery DNS", "description": "Ovládajte PiHole alebo AdGuard z ovládacieho panela", "option": { "layout": { @@ -974,68 +1110,87 @@ "label": "Vertikálne" }, "grid": { - "label": "" + "label": "Mriežka" } } }, "showToggleAllButtons": { - "label": "" + "label": "Zobraziť prepínač všetkých tlačidiel" } }, "error": { - "internalServerError": "" + "internalServerError": "Nepodarilo sa ovládať dieru DNS" }, "controls": { - "enableAll": "", - "disableAll": "", - "setTimer": "", + "enableAll": "Povoliť všetko", + "disableAll": "Zakázať všetko", + "setTimer": "Nastavte časovač", "set": "Nastaviť", "enabled": "Povolené", "disabled": "Zakázané", - "processing": "", - "disconnected": "", + "processing": "Spracovanie", + "disconnected": "Odpojené", "hours": "Hodiny", "minutes": "Minúty", - "unlimited": "" + "unlimited": "Ponechajte prázdne na neobmedzené" } }, "clock": { - "name": "", + "name": "Dátum a čas", "description": "Zobrazuje aktuálny dátum a čas.", "option": { "customTitleToggle": { - "label": "", - "description": "" + "label": "Vlastné zobrazenie názvu/mesta", + "description": "Pochváľte sa vlastným názvom alebo názvom mesta/krajiny v hornej časti hodín." }, "customTitle": { - "label": "" + "label": "Názov" }, "is24HourFormat": { - "label": "", - "description": "" + "label": "24-hodinový formát", + "description": "Namiesto 12-hodinového formátu použite 24-hodinový formát" }, "showSeconds": { - "label": "" + "label": "Zobrazte sekundy" }, "useCustomTimezone": { - "label": "" + "label": "Použite pevné časové pásmo" }, "timezone": { "label": "Časové pásmo", - "description": "" + "description": "Vyberte časové pásmo podľa štandardu IANA" }, "showDate": { - "label": "" + "label": "Zobrazenie dátumu" }, "dateFormat": { - "label": "", - "description": "" + "label": "Formát Dátumu", + "description": "Ako by mal dátum vyzerať" } } }, + "minecraftServerStatus": { + "name": "Minecraft Server Stav", + "description": "Zobraziť status Minecraft servera", + "option": { + "title": { + "label": "Názov" + }, + "domain": { + "label": "Adresa servera" + }, + "isBedrockServer": { + "label": "Bedrock server" + } + }, + "status": { + "online": "Online", + "offline": "Odpojené" + } + }, "notebook": { "name": "Poznámkový blok", - "description": "", + "description": "Jednoduchý widget poznámkového bloku, ktorý podporuje markdown", "option": { "showToolbar": { "label": "Zobrazenie panela nástrojov na pomoc pri písaní poznámok" @@ -1095,7 +1250,7 @@ } }, "iframe": { - "name": "", + "name": "iFrame", "description": "Vložte akýkoľvek obsah z internetu. Niektoré webové stránky môžu obmedziť prístup.", "option": { "embedUrl": { @@ -1127,31 +1282,32 @@ } }, "error": { - "noUrl": "", + "noUrl": "Nie je uvedená žiadna adresa URL iFrame", + "unsupportedProtocol": "Uvedená adresa URL používa nepodporovaný protokol. Použite jeden z ({supportedProtocols})", "noBrowerSupport": "Váš prehliadač nepodporuje iframe. Aktualizujte svoj prehliadač." } }, "smartHome-entityState": { - "name": "", - "description": "", + "name": "Stav subjektu", + "description": "Zobrazenie stavu entity a jej voliteľné prepínanie", "option": { "entityId": { "label": "ID subjektu" }, "displayName": { - "label": "" + "label": "Zobrazovaný názov" }, "entityUnit": { - "label": "" + "label": "Jednotka subjektu" }, "clickable": { - "label": "" + "label": "Klikateľné" } } }, "smartHome-executeAutomation": { - "name": "", - "description": "", + "name": "Vykonajte automatizáciu", + "description": "Spustite automatizáciu jedným kliknutím", "option": { "displayName": { "label": "Zobrazenie názvu" @@ -1161,26 +1317,26 @@ } }, "spotlightAction": { - "run": "" + "run": "Spustite {name}" } }, "calendar": { "name": "Kalendár", - "description": "", + "description": "Zobrazte udalosti z vašich integrácií v zobrazení kalendára za určité relatívne časové obdobie", "option": { "releaseType": { "label": "Typ Radarr releasu", "options": { - "inCinemas": "", - "digitalRelease": "", - "physicalRelease": "" + "inCinemas": "V kinách", + "digitalRelease": "Digitálne vydanie", + "physicalRelease": "Fyzické vydanie" } }, "filterPastMonths": { - "label": "" + "label": "Začať od" }, "filterFutureMonths": { - "label": "" + "label": "Koniec o" } } }, @@ -1189,24 +1345,24 @@ "description": "Zobrazí aktuálne informácie o počasí na nastavenom mieste.", "option": { "isFormatFahrenheit": { - "label": "" + "label": "Teplota vo stupňoch Fahrenheita" }, "location": { "label": "Poloha počasia" }, "showCity": { - "label": "" + "label": "Zobraziť mesto" }, "hasForecast": { - "label": "" + "label": "Zobraziť predpoveď" }, "forecastDayCount": { - "label": "", - "description": "" + "label": "Počet predpovedaných dní", + "description": "Keď miniaplikácia nie je dostatočne široká, zobrazí sa menej dní" }, "dateFormat": { - "label": "", - "description": "" + "label": "Formát Dátumu", + "description": "Ako by mal dátum vyzerať" } }, "kind": { @@ -1228,16 +1384,16 @@ }, "indexerManager": { "name": "Stav správcu indexovača", - "description": "", + "description": "Stav vašich indexátorov", "option": { "openIndexerSiteInNewTab": { - "label": "" + "label": "Otvoriť stránku indexera na novej karte" } }, "title": "Správca indexovača", "testAll": "Otestujte všetky", "error": { - "internalServerError": "" + "internalServerError": "Nepodarilo sa načítať stav indexerov" } }, "healthMonitoring": { @@ -1258,41 +1414,41 @@ } }, "popover": { - "information": "", - "processor": "", - "memory": "", - "memoryAvailable": "", - "version": "", - "uptime": "", - "loadAverage": "", - "minute": "", - "minutes": "", - "used": "", + "information": "Informácie", + "processor": "Procesor: {cpuModelName}", + "memory": "Pamäť: {memory}GiB", + "memoryAvailable": "K dispozícii: {memoryAvailable}GiB ({percent}%)", + "version": "Verzia: {version}", + "uptime": "Doba prevádzky: {days} dní, {hours} hodín, {minutes} minút", + "loadAverage": "Priemerné zaťaženie:", + "minute": "1 minúta", + "minutes": "{count} minút", + "used": "Použité", "available": "K dispozícii", - "lastSeen": "" + "lastSeen": "Posledná aktualizácia stavu: {lastSeen}" }, "memory": {}, "error": { - "internalServerError": "" + "internalServerError": "Nepodarilo sa načítať zdravotný stav" } }, "common": { "location": { - "query": "", - "latitude": "", - "longitude": "", - "disabledTooltip": "", - "unknownLocation": "", + "query": "Mesto / PSČ", + "latitude": "Zemepisná šírka", + "longitude": "Zemepisná dĺžka", + "disabledTooltip": "Zadajte mesto alebo poštové smerovacie číslo", + "unknownLocation": "Neznáma poloha", "search": "Hladať", "table": { "header": { - "city": "", - "country": "", - "coordinates": "", - "population": "" + "city": "Mesto", + "country": "Krajina", + "coordinates": "Súradnice", + "population": "Populácia" }, "action": { - "select": "" + "select": "Vyberte {city}, {countryCode}" }, "population": { "fallback": "Neznámy" @@ -1300,19 +1456,16 @@ } }, "integration": { - "noData": "", - "description": "" + "noData": "Nenašla sa žiadna integrácia", + "description": "Kliknutím na vytvoríte novú integráciu" }, "app": { - "noData": "", - "description": "" + "noData": "Nenašla sa žiadna aplikácia", + "description": "Kliknutím na vytvorte novú aplikáciu" }, "error": { - "action": { - "logs": "" - }, - "noIntegration": "", - "noData": "" + "noIntegration": "Nie je vybraná žiadna integrácia", + "noData": "Nie sú k dispozícii žiadne údaje o integrácii" }, "option": {} }, @@ -1325,128 +1478,133 @@ }, "hasAutoPlay": { "label": "Automatické prehrávanie", - "description": "" + "description": "Automatické prehrávanie funguje iba pri vypnutom zvuku z dôvodu obmedzení prehliadača" }, "isMuted": { - "label": "" + "label": "Stíšené" }, "hasControls": { - "label": "" + "label": "Zobraziť ovládacie prvky" } }, "error": { - "noUrl": "", - "forYoutubeUseIframe": "" + "noUrl": "Neposkytnutá adresa URL videa", + "forYoutubeUseIframe": "Pre videá YouTube použite možnosť iframe" } }, "mediaServer": { - "name": "", - "description": "", - "option": {} + "name": "Aktuálne streamy mediálneho servera", + "description": "Zobrazte aktuálne streamy na vašich mediálnych serveroch", + "option": {}, + "items": { + "user": "Používateľ", + "name": "Názov", + "id": "Id" + } }, "downloads": { - "name": "", - "description": "", + "name": "Download klient", + "description": "Umožňuje vám zobraziť a spravovať stiahnuté súbory z klientov Torrent aj Usenet.", "option": { "columns": { - "label": "" + "label": "Stĺpce na zobrazenie" }, "enableRowSorting": { - "label": "" + "label": "Povoliť triedenie položiek" }, "defaultSort": { - "label": "" + "label": "Stĺpec používaný na triedenie v predvolenom nastavení" }, "descendingDefaultSort": { - "label": "" + "label": "Inverzné triedenie" }, "showCompletedUsenet": { - "label": "" + "label": "Zobrazenie záznamov v sieti Usenet označených ako dokončené" }, "showCompletedTorrent": { - "label": "" + "label": "Zobraziť položky torrentu označené ako dokončené" }, "activeTorrentThreshold": { - "label": "" + "label": "Skryť dokončený torrent pod touto hranicou (v kiB/s)" }, "categoryFilter": { - "label": "" + "label": "Kategórie/značky na filtrovanie" }, "filterIsWhitelist": { - "label": "" + "label": "Filter ako biely zoznam" }, "applyFilterToRatio": { - "label": "" + "label": "Na výpočet pomeru použite filter" } }, "errors": { - "noColumns": "", - "noCommunications": "" + "noColumns": "Vyberte položku Stĺpce v položkách", + "noCommunications": "Nie je možné načítať údaje z integrácie" }, "items": { "actions": { - "columnTitle": "" + "columnTitle": "Ovládacie prvky" }, "added": { - "columnTitle": "", + "columnTitle": "Pridané", "detailsTitle": "Dátum pridania" }, "category": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Doplnky", + "detailsTitle": "Kategórie (alebo ďalšie informácie)" }, "downSpeed": { "columnTitle": "Dole", "detailsTitle": "Rýchlosť sťahovania" }, "index": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "#", + "detailsTitle": "Aktuálny index v rámci klienta" }, "id": { - "columnTitle": "" + "columnTitle": "Id" }, "integration": { "columnTitle": "Integrácia" }, "name": { - "columnTitle": "" + "columnTitle": "Názov úlohy" }, "progress": { "columnTitle": "Stav", - "detailsTitle": "" + "detailsTitle": "Priebeh sťahovania" }, "ratio": { "columnTitle": "Pomer", - "detailsTitle": "" + "detailsTitle": "Pomer torrentu (prijaté/odoslané)" }, "received": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Celkom dole", + "detailsTitle": "Celkovo stiahnuté" }, "sent": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Celkom hore", + "detailsTitle": "Celkovo nahrané" }, "size": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Veľkosť súboru", + "detailsTitle": "Celková veľkosť výberu/súborov" }, "state": { "columnTitle": "Stav", - "detailsTitle": "" + "detailsTitle": "Stav práce" }, "time": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Čas ukončenia", + "detailsTitle": "Čas od/do dokončenia" }, "type": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Typ", + "detailsTitle": "Typ Download klienta" }, "upSpeed": { "columnTitle": "Hore", - "detailsTitle": "" + "detailsTitle": "Rýchlosť uploadu " } }, "states": { @@ -1454,38 +1612,38 @@ "queued": "V poradí", "paused": "Pozastavené", "completed": "Dokončené", - "failed": "", - "processing": "", - "leeching": "", - "stalled": "", + "failed": "Neúspešné", + "processing": "Spracovanie", + "leeching": "Leech", + "stalled": "Zastavené", "unknown": "Neznámy", - "seeding": "" + "seeding": "Distribúcia" }, "actions": { "clients": { - "modalTitle": "", - "pause": "", - "resume": "" + "modalTitle": "Zoznam Download klientov", + "pause": "Pozastaviť všetkých klientov/položky", + "resume": "Obnovte všetkých klientov/položky" }, "client": { - "pause": "", - "resume": "" + "pause": "Pozastaviť klienta", + "resume": "Obnoviť klienta" }, "item": { - "pause": "", - "resume": "", + "pause": "Pozastaviť položku", + "resume": "Obnoviť položku", "delete": { - "title": "", - "modalTitle": "", - "entry": "", - "entryAndFiles": "" + "title": "Odstrániť položku", + "modalTitle": "Naozaj chcete odstrániť túto úlohu?", + "entry": "Odstrániť záznam", + "entryAndFiles": "Odstrániť záznam a súbor(y)" } } }, - "globalRatio": "" + "globalRatio": "Globálny pomer" }, "mediaRequests-requestList": { - "name": "", + "name": "Zoznam mediálnych požiadaviek", "description": "Zobrazenie zoznamu všetkých mediálnych požiadaviek z Overseerr alebo Jellyseerr", "option": { "linksTargetNewTab": { @@ -1493,21 +1651,21 @@ } }, "pending": { - "approve": "", - "approving": "", - "decline": "" + "approve": "Schváliť žiadosť", + "approving": "Schválenie žiadosti...", + "decline": "Zamietnuť žiadost" }, "availability": { "unknown": "Neznámy", - "pending": "", - "processing": "", + "pending": "Čakajúce", + "processing": "Spracovanie", "partiallyAvailable": "Čiastočný", "available": "K dispozícii" }, - "toBeDetermined": "" + "toBeDetermined": "TBD" }, "mediaRequests-requestStats": { - "name": "", + "name": "Štatistiky mediálnych žiadostí", "description": "Štatistiky o vašich požiadavkách na médiá", "option": {}, "titles": { @@ -1515,98 +1673,172 @@ "main": "Štatistiky médií", "approved": "Už schválené", "pending": "Čakajúce na schválenie", - "processing": "", - "declined": "", - "available": "", + "processing": "Spracováva sa", + "declined": "Už odmietnuté", + "available": "Už k dispozícii", "tv": "TV požiadavky", "movie": "Filmové požiadavky", "total": "Celkom" }, "users": { "main": "Najlepší používatelia", - "requests": "" + "requests": "Požiadavky" + } + } + }, + "mediaTranscoding": { + "name": "Prekódovanie médií", + "description": "Štatistiky, aktuálny stav frontu a pracovníkov pri prekódovaní médií", + "option": { + "defaultView": { + "label": "Predvolené zobrazenie" + }, + "queuePageSize": { + "label": "Veľkosť stránky frontu" + } + }, + "tab": { + "workers": "Pracovníci", + "queue": "Fronta", + "statistics": "Statistiky" + }, + "currentIndex": "{start}-{end} z {total}", + "healthCheck": { + "title": "Kontrola stavu", + "queued": "V poradí", + "status": { + "healthy": "Zdravý", + "unhealthy": "Nezdravý" + } + }, + "panel": { + "statistics": { + "empty": "Prázdny", + "transcodes": "Transkodér", + "transcodesCount": "Transkódy: {value}", + "healthChecksCount": "Zdravotné kontroly: {value}", + "filesCount": "Súbory: {value}", + "savedSpace": "Ušetrené miesto: {value}", + "healthChecks": "Kontrola stavu", + "videoCodecs": "Kodeky", + "videoContainers": "Kontajnery", + "videoResolutions": "Rozlíšenie" + }, + "workers": { + "empty": "Prázdny", + "table": { + "file": "Súbor", + "eta": "Odhad", + "progress": "Stav", + "transcode": "Transkodér", + "healthCheck": "Kontrola stavu" + } + }, + "queue": { + "empty": "Prázdny", + "table": { + "file": "Súbor", + "size": "Veľkosť", + "transcode": "Transkodér", + "healthCheck": "Kontrola stavu" + } } } }, "rssFeed": { - "name": "", - "description": "", + "name": "RSS kanály", + "description": "Monitorujte a zobrazujte jeden alebo viac všeobecných informačných kanálov RSS, ATOM alebo JSON", "option": { "feedUrls": { - "label": "" + "label": "Adresa URL" }, "enableRtl": { - "label": "" + "label": "Povoliť RTL" }, "textLinesClamp": { - "label": "" + "label": "Svorka popisnej línie" }, "maximumAmountPosts": { - "label": "" + "label": "Limit počtu príspevkov" } } } }, "widgetPreview": { "toggle": { - "enabled": "", - "disabled": "" + "enabled": "Režim úprav je povolený", + "disabled": "Režim úprav je zakázaný" }, "dimensions": { - "title": "" + "title": "Zmeniť rozmery" } }, "board": { "action": { + "duplicate": { + "title": "Duplikovať dosku", + "message": "Tým sa duplikuje nástenka {name} s celým jej obsahom. Ak widgety odkazujú na integrácie, ktoré nemáte povolené používať, budú odstránené.", + "notification": { + "success": { + "title": "Doska duplikovaná", + "message": "Doska bola úspešne duplikovaná" + }, + "error": { + "title": "Nieje možné duplikovať dosku", + "message": "Tabuľu nebolo možné duplikovať" + } + } + }, "edit": { "notification": { "success": { - "title": "", - "message": "" + "title": "Zmeny boli úspešne použité", + "message": "Doska bola úspešne uložená" }, "error": { - "title": "", - "message": "" + "title": "Nie je možné použiť zmeny", + "message": "Tabuľu sa nepodarilo uložiť" } }, "confirmLeave": { - "title": "", - "message": "" + "title": "Neuložené zmeny", + "message": "Máte neuložené zmeny. Naozaj chcete odísť?" } }, "oldImport": { - "label": "", + "label": "Import z homarru pred 1.0.0", "notification": { "success": { - "title": "", - "message": "" + "title": "Import úspešný", + "message": "Doska bola úspešne importovaná" }, "error": { - "title": "", - "message": "" + "title": "Import zlyhal.", + "message": "Dosku sa nepodarilo importovať, ďalšie podrobnosti nájdete v záznamoch" } }, "form": { "file": { - "label": "", - "invalidError": "" + "label": "Vyberte súbor JSON", + "invalidError": "Neplatný konfiguračný súbor" }, "apps": { "label": "Aplikácie", "avoidDuplicates": { - "label": "", - "description": "" + "label": "Vyhnite sa duplikátom", + "description": "Ignoruje aplikácie, v ktorých už existuje aplikácia s rovnakým href" }, "onlyImportApps": { - "label": "", - "description": "" + "label": "Importujte iba aplikácie", + "description": "Pridá len aplikácie, dosku je potrebné vytvoriť znova ručne" } }, "name": { - "label": "" + "label": "Názov dosky" }, "screenSize": { - "label": "", + "label": "Veľkosť obrazovky", + "description": "Vo verziách pred 1.0 existovali tri rôzne režimy, takže ste si mohli vybrať množstvo stĺpcov pre každú veľkosť obrazovky.", "option": { "sm": "Malé", "md": "Stredné", @@ -1614,16 +1846,16 @@ } }, "sidebarBehavior": { - "label": "", - "description": "", + "label": "Správanie bočného panela", + "description": "Bočné panely boli odstránené vo verzii 1.0, môžete si vybrať, čo sa má stať s položkami v nich.", "option": { "lastSection": { - "label": "", - "description": "" + "label": "Posledná sekcia", + "description": "Pod poslednou sekciou sa zobrazí bočný panel" }, "removeItems": { - "label": "", - "description": "" + "label": "Odstrániť položky", + "description": "Položky na bočnom paneli budú odstránené" } } } @@ -1632,51 +1864,51 @@ }, "field": { "pageTitle": { - "label": "" + "label": "Názov stránky" }, "metaTitle": { - "label": "" + "label": "Meta názov" }, "logoImageUrl": { - "label": "" + "label": "Adresa URL obrázka loga" }, "faviconImageUrl": { - "label": "" + "label": "Adresa URL obrázka Favicon" }, "backgroundImageUrl": { - "label": "" + "label": "URL obrázku pozadia" }, "backgroundImageAttachment": { "label": "Pripojenie obrázku na pozadí", "option": { "fixed": { - "label": "", - "description": "" + "label": "Pevné", + "description": "Pozadie zostáva v rovnakej polohe." }, "scroll": { - "label": "", - "description": "" + "label": "Posun", + "description": "Pozadie sa posúva pomocou myši." } } }, "backgroundImageRepeat": { - "label": "", + "label": "Opakovanie obrázka na pozadí", "option": { "repeat": { - "label": "", - "description": "" + "label": "Opakovať", + "description": "Obrázok sa opakuje toľko, koľko je potrebné, aby pokryl celú plochu maľby obrázka na pozadí." }, "no-repeat": { - "label": "", - "description": "" + "label": "Žiadne opakovanie", + "description": "Obrázok sa neopakuje a nemusí vyplniť celý priestor." }, "repeat-x": { - "label": "", - "description": "" + "label": "Opakujte X", + "description": "Rovnaké ako „Opakovať“, ale iba na vodorovnej osi." }, "repeat-y": { - "label": "", - "description": "" + "label": "Opakujte Y", + "description": "Rovnaké ako „Opakovať“, ale iba na zvislej osi." } } }, @@ -1684,12 +1916,12 @@ "label": "Veľkosť obrázka na pozadí", "option": { "cover": { - "label": "", - "description": "" + "label": "Obálka", + "description": "Zmení mierku obrazu čo najmenšiu, aby pokryl celé okno orezaním nadmerného priestoru." }, "contain": { - "label": "", - "description": "" + "label": "Obsahuje", + "description": "Zväčší veľkosť obrázka v rámci jeho kontajnera na čo najväčšiu mieru bez orezania alebo roztiahnutia obrázka." } } }, @@ -1700,36 +1932,36 @@ "label": "Sekundárna farba" }, "opacity": { - "label": "" + "label": "Priehľadnosť" }, "customCss": { - "label": "", + "label": "Vlastné css pre túto nástenku", "description": "Ďalej si prispôsobte ovládací panel pomocou CSS, odporúča sa len pre skúsených používateľov", "customClassesAlert": { - "title": "", - "description": "" + "title": "Vlastné triedy", + "description": "Vlastné triedy môžete pridať k položkám nástenky v rozšírených možnostiach každej položky a použiť ich vo vlastnom CSS vyššie." } }, "columnCount": { - "label": "" + "label": "Počet stĺpcov" }, "name": { "label": "Názov" }, "isPublic": { "label": "Verejné", - "description": "" + "description": "Verejné tabule sú prístupné každému, dokonca aj bez účtu." } }, "content": { - "metaTitle": "" + "metaTitle": "{boardName} doska" }, "setting": { - "title": "", + "title": "Nastavenia dosky {boardName}", "section": { "general": { "title": "Všeobecné", - "unrecognizedLink": "" + "unrecognizedLink": "Poskytnutý odkaz nie je rozpoznaný a nezobrazí sa ukážka, môže stále fungovať." }, "layout": { "title": "Rozloženie" @@ -1738,23 +1970,23 @@ "title": "Pozadie" }, "color": { - "title": "" + "title": "Farby" }, "customCss": { - "title": "" + "title": "Vlastné css" }, "access": { - "title": "", + "title": "Kontrola prístupu", "permission": { "item": { "view": { "label": "Zobraziť tabuľu" }, "modify": { - "label": "" + "label": "Upraviť dosku" }, "full": { - "label": "" + "label": "Plný prístup" } } } @@ -1763,82 +1995,115 @@ "title": "Nebezpečná zóna", "action": { "rename": { - "label": "", - "description": "", - "button": "", + "label": "Premenovať tabuľu", + "description": "Zmenou názvu sa prerušia všetky odkazy na túto nástenku.", + "button": "Zmeniť názov", "modal": { - "title": "" + "title": "Premenovať tabuľu" } }, "visibility": { - "label": "", + "label": "Zmena viditeľnosti dosky", "description": { - "public": "", - "private": "" + "public": "Táto tabuľa je momentálne verejná.", + "private": "Táto tabuľa je momentálne súkromná." }, "button": { - "public": "", - "private": "" + "public": "Zmeniť na súkromné", + "private": "Zmeniť na verejné" }, "confirm": { "public": { - "title": "", - "description": "" + "title": "Nastaviť tabuľu ako súkromnú", + "description": "Naozaj chcete nastaviť túto nástenku ako súkromnú? Tým sa tabuľa skryje pred verejnosťou. Odkazy pre hosťujúcich používateľov sa pokazia." }, "private": { - "title": "", - "description": "" + "title": "Zverejnite nástenku", + "description": "Naozaj chcete zverejniť túto nástenku? Vďaka tomu bude tabuľa dostupná pre každého." } } }, "delete": { - "label": "", - "description": "", - "button": "", + "label": "Odstrániť túto nástenku", + "description": "Keď odstránite nástenku, už niet cesty späť. Buďte si istí.", + "button": "Odstrániť túto nástenku", "confirm": { "title": "Odstrániť dosku", - "description": "" + "description": "Naozaj chcete odstrániť túto nástenku? Tým sa natrvalo odstráni nástenka a všetok jej obsah." } } } } } + }, + "error": { + "noBoard": { + "title": "Vitajte na stránke Homarr", + "description": "Elegantný moderný prístrojový panel, ktorý dáva všetky vaše aplikácie a služby na dosah ruky.", + "link": "Vytvorte si svoju prvú nástenku", + "notice": "Aby táto stránka zmizla, vytvorte nástenku a nastavte ju ako domácu nástenku" + }, + "notFound": { + "title": "Tabuľa sa nenašla", + "description": "Zadaná doska sa buď nenašla, alebo k nej nemáte prístup.", + "link": "Zobraziť všetky dosky", + "notice": "Skontrolujte odkaz alebo kontaktujte správcu, ak si myslíte, že by mal byť prístupný" + }, + "homeBoard": { + "title": "Žiadna domáca doska", + "admin": { + "description": "Ešte ste nenastavili domovskú nástenku pre server.", + "link": "Konfigurácia domácej dosky pre celý server", + "notice": "Ak chcete, aby táto stránka zmizla pre všetkých používateľov, nastavte domovskú dosku pre server" + }, + "user": { + "description": "Ešte ste nenastavili domácu nástenku.", + "link": "Nakonfigurujte si domácu dosku", + "notice": "Ak chcete, aby táto stránka zmizla, zadajte domovskú nástenku vo svojich preferenciách" + }, + "anonymous": { + "description": "Správca servera ešte nenastavil domácu nástenku.", + "link": "Pozrite si verejné nástenky", + "notice": "Ak chcete, aby táto stránka zmizla, požiadajte správcu servera o nastavenie domovskej dosky pre server" + } + } } }, "management": { - "metaTitle": "", + "metaTitle": "Administrácia", "title": { - "morning": "", - "afternoon": "", - "evening": "" + "morning": "Dobré ráno, {username}", + "afternoon": "Dobré popoludnie, {username}", + "evening": "Dobrý večer, {username}" }, "notFound": { - "title": "", - "text": "" + "title": "Nenájdené", + "text": "Nepodarilo sa nájsť požadovaný zdroj" }, "navbar": { "items": { "home": "Domovská stránka", "boards": "Dosky", "apps": "Aplikácie", - "integrations": "", - "searchEngies": "", - "medias": "", + "integrations": "Integrácie", + "searchEngies": "Vyhľadávače", + "medias": "Médiá", "users": { "label": "Používatelia", "items": { "manage": "Spravovať", "invites": "Pozvánky", - "groups": "" + "groups": "Skupiny" } }, "tools": { "label": "Nástroje", "items": { - "docker": "", - "logs": "", - "api": "", - "tasks": "" + "docker": "Docker", + "logs": "Záznamy", + "api": "API", + "certificates": "", + "tasks": "Úlohy" } }, "settings": "Nastavenia", @@ -1846,9 +2111,9 @@ "label": "Pomocník", "items": { "documentation": "Dokumentácia", - "submitIssue": "", + "submitIssue": "Odoslať problém", "discord": "Diskord Spoločenstva", - "sourceCode": "" + "sourceCode": "Zdrojový kód" } }, "about": "O aplikácii" @@ -1860,47 +2125,57 @@ "board": "Dosky", "user": "Používatelia", "invite": "Pozvánky", - "integration": "", + "integration": "Integrácie", "app": "Aplikácie", - "group": "" + "group": "Skupiny" }, "statisticLabel": { "boards": "Dosky", - "resources": "", - "authentication": "", - "authorization": "" + "resources": "Zdroje", + "authentication": "Autentifikácia", + "authorization": "Autorizácia" } }, "board": { "title": "Vaše dosky", "action": { "new": { - "label": "" + "label": "Nová doska" }, "open": { - "label": "" + "label": "Otvoriť dosku" }, "settings": { "label": "Nastavenia" }, "setHomeBoard": { - "label": "", + "label": "Nastavenie ako predvolenej dosky", "badge": { "label": "Domovská stránka", - "tooltip": "" + "tooltip": "Táto tabuľa sa zobrazí ako vaša domovská tabuľa" } }, + "setMobileHomeBoard": { + "label": "Nastaviť ako mobilnú tabuľu", + "badge": { + "label": "Mobilný", + "tooltip": "Táto tabuľa sa zobrazí ako vaša mobilná tabuľa" + } + }, + "duplicate": { + "label": "Duplikovať dosku" + }, "delete": { "label": "Odstrániť natrvalo", "confirm": { "title": "Odstrániť dosku", - "description": "" + "description": "Naozaj chcete odstrániť nástenku {name} ?" } } }, "visibility": { - "public": "", - "private": "" + "public": "Táto tabuľa je verejná", + "private": "Táto tabuľa je súkromná" }, "modal": { "createBoard": { @@ -1913,17 +2188,24 @@ } }, "media": { - "includeFromAllUsers": "" + "includeFromAllUsers": "Zahrnúť médiá od všetkých používateľov" }, "user": { - "back": "", - "fieldsDisabledExternalProvider": "", + "back": "Späť k používateľom", + "fieldsDisabledExternalProvider": "Niektoré polia sú zakázané, pretože ich spravuje externý poskytovateľ autentifikácie.", "setting": { "general": { "title": "Všeobecné", "item": { - "language": "", - "board": "", + "language": "Jazyk a región", + "board": { + "title": "Domáca doska", + "type": { + "general": "Hlavné", + "mobile": "Mobilná" + } + }, + "defaultSearchEngine": "Predvolený vyhľadávací nástroj", "firstDayOfWeek": "Prvý deň v týždni", "accessibility": "Prístupnosť" } @@ -1940,50 +2222,50 @@ "title": "Používatelia" }, "edit": { - "metaTitle": "" + "metaTitle": "Upraviť používateľa {username}" }, "create": { "metaTitle": "Vytvoriť užívateľa", - "title": "", + "title": "Vytvoriť nového používateľa", "step": { "personalInformation": { - "label": "" + "label": "Osobné údaje" }, "security": { "label": "Bezpečnosť" }, "groups": { - "label": "", - "title": "", - "description": "" + "label": "Skupiny", + "title": "Vyberte všetky skupiny, ktorých by mal byť používateľ členom", + "description": "Skupina {everyoneGroup} je priradená všetkým používateľom a nemožno ju odstrániť." }, "review": { - "label": "" + "label": "Prehľad" }, "completed": { - "title": "" + "title": "Používateľ vytvorený" }, "error": { - "title": "" + "title": "Vytvorenie užívateľa zlyhalo" } }, "action": { - "createAnother": "", - "back": "" + "createAnother": "Vytvorte ďalšieho používateľa", + "back": "Vráťte sa do zoznamu používateľov" } }, "invite": { "title": "Správa pozvánok používateľov", "action": { "new": { - "title": "", + "title": "Nová pozvánka", "description": "Po vypršaní platnosti pozvánky už nebude platná a príjemca pozvánky si nebude môcť vytvoriť účet." }, "copy": { - "title": "", - "description": "", + "title": "Skopírujte pozvánku", + "description": "Vaša pozvánka bola vygenerovaná. Po zatvorení tohto modálu už tento odkaz nebudete môcť kopírovať. Ak už nechcete pozývať uvedenú osobu, môžete túto pozvánku kedykoľvek vymazať.", "link": "Odkaz na pozvánku", - "button": "" + "button": "Kopírovať a zavrieť" }, "delete": { "title": "Odstránenie pozvánky", @@ -1992,7 +2274,7 @@ }, "field": { "id": { - "label": "" + "label": "ID" }, "creator": { "label": "Autor" @@ -2001,29 +2283,29 @@ "label": "Dátum vypršania" }, "token": { - "label": "" + "label": "Token" } } } }, "group": { - "back": "", + "back": "Späť na skupiny", "setting": { "general": { "title": "Všeobecné", - "owner": "", - "ownerOfGroup": "", - "ownerOfGroupDeleted": "" + "owner": "Vlastník", + "ownerOfGroup": "Vlastník tejto skupiny", + "ownerOfGroupDeleted": "Vlastník tejto skupiny bol odstránený. V súčasnosti nemá žiadneho vlastníka." }, "members": { - "title": "", - "search": "", - "notFound": "" + "title": "Členovia", + "search": "Nájdite člena", + "notFound": "Nenašli sa žiadni členovia" }, "permissions": { - "title": "", + "title": "Povolenia", "form": { - "unsavedChanges": "" + "unsavedChanges": "Máš neuložené zmeny!" } } } @@ -2032,137 +2314,154 @@ "title": "Nastavenia", "notification": { "success": { - "message": "" + "message": "Nastavenie bolo uložené" }, "error": { - "message": "" + "message": "Nepodarilo sa uložiť nastavenia" } }, "section": { "analytics": { - "title": "", + "title": "Analytika", "general": { - "title": "", - "text": "" + "title": "Odoslať anonymné analýzy", + "text": "Homarr bude posielať anonymizované analýzy pomocou open source softvéru Umami. Nikdy nezhromažďuje žiadne osobné údaje, a preto je plne v súlade s GDPR a CCPA. Odporúčame vám povoliť analýzu, pretože pomáha nášmu tímu s otvoreným zdrojom identifikovať problémy a uprednostňovať naše nevybavené veci." }, "widgetData": { - "title": "", - "text": "" + "title": "Údaje widgetu", + "text": "Pošlite, ktoré widgety (a ich množstvo) ste nakonfigurovali. Nezahŕňa adresy URL, mená ani iné údaje." }, "integrationData": { - "title": "", - "text": "" + "title": "Integračné údaje", + "text": "Pošlite, ktoré integrácie (a ich množstvo) ste nakonfigurovali. Nezahŕňa adresy URL, mená ani iné údaje." }, "usersData": { - "title": "", - "text": "" + "title": "Údaje o používateľoch", + "text": "Pošlite počet používateľov a či ste aktivovali jednotné prihlásenie" } }, "crawlingAndIndexing": { - "title": "", - "warning": "", + "title": "Prehľadávanie a indexovanie", + "warning": "Povolenie alebo zakázanie akýchkoľvek nastavení tu výrazne ovplyvní spôsob, akým vyhľadávacie nástroje indexujú a indexovo prehľadávajú vašu stránku. Akékoľvek nastavenie je požiadavka a je na indexovom prehľadávači, aby tieto nastavenia použil. Uplatnenie akejkoľvek úpravy môže trvať niekoľko dní alebo týždňov. Niektoré nastavenia môžu byť špecifické pre vyhľadávače.", "noIndex": { - "title": "", - "text": "" + "title": "Žiadny index", + "text": "Neindexujte webovú stránku vo vyhľadávačoch a nezobrazujte ju v žiadnych výsledkoch vyhľadávania" }, "noFollow": { - "title": "", - "text": "" + "title": "Žiadne sledovanie", + "text": "Počas indexovania nesledujte žiadne odkazy. Zakázanie tohto povedie k tomu, že sa prehľadávače pokúsia sledovať všetky odkazy na Homarr." }, "noTranslate": { - "title": "", - "text": "" + "title": "Žiadny preklad", + "text": "Ak jazyk stránky pravdepodobne nebude chcieť čítať používateľ, Google vo výsledkoch vyhľadávania zobrazí odkaz na preklad" }, "noSiteLinksSearchBox": { - "title": "", - "text": "" + "title": "Žiadne vyhľadávacie pole odkazov na stránky", + "text": "Google vytvorí vyhľadávacie pole s prehľadávanými odkazmi spolu s ďalšími priamymi odkazmi. Ak to povolíte, Google požiada o deaktiváciu tohto poľa." } }, "board": { - "title": "", + "title": "Dosky", "homeBoard": { - "label": "", - "description": "" + "label": "Globálna domovská nástenka", + "mobileLabel": "Globálna mobilná doska", + "description": "Na výber sú k dispozícii iba verejné tabule" + } + }, + "search": { + "title": "Hladať", + "defaultSearchEngine": { + "label": "Predvolený vyhľadávací nástroj", + "description": "Integračné vyhľadávače tu nie je možné vybrať" } }, "appearance": { - "title": "", + "title": "Vzhľad", "defaultColorScheme": { - "label": "", + "label": "Predvolená farebná schéma", "options": { - "light": "", - "dark": "" + "light": "Svetlý", + "dark": "Tmavý" } } }, "culture": { - "title": "", + "title": "Kultúra", "defaultLocale": { - "label": "" + "label": "Predvolený jazyk" } } } }, "tool": { "tasks": { - "title": "", + "title": "Úlohy", "status": { - "idle": "", + "idle": "Nečinný", "running": "Spustené", "error": "Chyba" }, "job": { + "minecraftServerStatus": { + "label": "Minecraft Server Stav" + }, "iconsUpdater": { - "label": "" + "label": "Aktualizátor ikon" }, "analytics": { - "label": "" + "label": "Analytika" }, "smartHomeEntityState": { - "label": "" + "label": "Stav entity inteligentnej domácnosti" }, "ping": { - "label": "" + "label": "Pingy" }, "mediaServer": { "label": "Multimediálny Server" }, "mediaOrganizer": { - "label": "" + "label": "Organizátori médií" }, "downloads": { - "label": "" + "label": "Na stiahnutie" }, "mediaRequestStats": { - "label": "" + "label": "Štatistiky mediálnych požiadaviek" }, "mediaRequestList": { - "label": "" + "label": "Zoznam mediálnych požiadaviek" }, "rssFeeds": { - "label": "" + "label": "RSS kanály" }, "indexerManager": { - "label": "" + "label": "Správca indexovania" }, "healthMonitoring": { - "label": "" + "label": "Monitorovanie zdravia" }, "dnsHole": { - "label": "" + "label": "Údaje o dierach DNS" }, "sessionCleanup": { - "label": "" + "label": "Čistenie relácie" + }, + "updateChecker": { + "label": "Kontrola aktualizácií" + }, + "mediaTranscoding": { + "label": "Prekódovanie médií" } } }, "api": { - "title": "", + "title": "API", "modal": { "createApiToken": { - "title": "", - "description": "", - "button": "" + "title": "Vytvorený token API", + "description": "Token API bol vytvorený. Buďte opatrní, tento token je v databáze zašifrovaný a už sa vám nikdy neprenesie. Ak tento token stratíte, už nebudete môcť tento konkrétny token získať.", + "button": "Kopírovať a zatvoriť" } }, "tab": { @@ -2170,15 +2469,15 @@ "label": "Dokumentácia" }, "apiKey": { - "label": "", - "title": "", + "label": "Autentifikácia", + "title": "API kľúče", "button": { - "createApiToken": "" + "createApiToken": "Vytvorte token API" }, "table": { "header": { - "id": "", - "createdBy": "" + "id": "ID", + "createdBy": "Vytvoril/a" } } } @@ -2186,20 +2485,20 @@ } }, "about": { - "version": "", - "text": "", + "version": "Verzia {version}", + "text": "Homarr je komunitou riadený open source projekt, ktorý spravujú dobrovoľníci. Vďaka týmto ľuďom je Homarr rastúcim projektom od roku 2021. Náš tím pracuje na Homarre úplne ďaleko od mnohých rôznych krajín vo svojom voľnom čase bez akejkoľvek kompenzácie.", "accordion": { "contributors": { - "title": "", - "subtitle": "" + "title": "Prispievatelia", + "subtitle": "{count} udržiavanie kódu & Homarr" }, "translators": { - "title": "", - "subtitle": "" + "title": "Prekladatelia", + "subtitle": "{count} prispievanie prekladmi do mnohých jazykov" }, "libraries": { - "title": "", - "subtitle": "" + "title": "Knižnice", + "subtitle": "{count} používané v Homarrskom kódexe" } } } @@ -2208,9 +2507,9 @@ "docker": { "title": "Kontajnery", "table": { - "updated": "", - "search": "", - "selected": "" + "updated": "Aktualizované {when}", + "search": "Vyhľadajte {count} kontajnery", + "selected": "{selectCount} z {totalCount} vybratých kontajnerov" }, "field": { "name": { @@ -2223,9 +2522,9 @@ "running": "Spustené", "paused": "Pozastavené", "restarting": "Reštartovanie", - "exited": "", + "exited": "Ukončené", "removing": "Odstraňujem", - "dead": "" + "dead": "Mŕtvy" } }, "containerImage": { @@ -2240,12 +2539,12 @@ "label": "Spustiť", "notification": { "success": { - "title": "", - "message": "" + "title": "Spustili sa kontajnery", + "message": "Kontajnery boli úspešne spustené" }, "error": { - "title": "", - "message": "" + "title": "Kontajnery nie sú spustené", + "message": "Kontajnery nebolo možné spustiť" } } }, @@ -2253,12 +2552,12 @@ "label": "Zastaviť", "notification": { "success": { - "title": "", - "message": "" + "title": "Kontajnery sa zastavili", + "message": "Kontajnery boli úspešne zastavené" }, "error": { - "title": "", - "message": "" + "title": "Kontajnery nezastavené", + "message": "Kontajnery sa nedali zastaviť" } } }, @@ -2266,12 +2565,12 @@ "label": "Reštartovať", "notification": { "success": { - "title": "", - "message": "" + "title": "Kontajnery boli reštartované", + "message": "Kontajnery boli úspešne reštartované" }, "error": { - "title": "", - "message": "" + "title": "Kontajnery neboli reštartované", + "message": "Kontajnery nebolo možné reštartovať" } } }, @@ -2279,57 +2578,76 @@ "label": "Odstrániť", "notification": { "success": { - "title": "", - "message": "" + "title": "Kontajnery boli odstránené", + "message": "Kontajnery boli úspešne odstránené" }, "error": { - "title": "", - "message": "" + "title": "Neodstránené kontajnery", + "message": "Kontajnery nebolo možné odstrániť" } } }, "refresh": { - "label": "", + "label": "Obnoviť", "notification": { "success": { - "title": "", - "message": "" + "title": "Obnovenie kontajnerov", + "message": "Teraz si prezeráte najnovšie údaje" }, "error": { - "title": "", - "message": "" + "title": "Kontajnery nie sú obnovené", + "message": "Pri obnovovaní kontajnerov sa niečo pokazilo" } } + }, + "addToHomarr": { + "label": "Pridať do Homarr", + "notification": { + "success": { + "title": "Pridané do Homarr", + "message": "Vybrané aplikácie boli pridané do Homarr" + }, + "error": { + "title": "Nepodarilo sa pridať do Homarr", + "message": "Vybrané aplikácie nebolo možné pridať do Homarr" + } + }, + "modal": { + "title": "Pridajte docker kontajner/y do Homarr" + } } + }, + "error": { + "internalServerError": "Nepodarilo sa načítať kontajnery Docker" } }, "permission": { - "title": "", + "title": "Povolenia", "userSelect": { - "title": "" + "title": "Pridať povolenie používateľa" }, "groupSelect": { - "title": "" + "title": "Pridať skupinové povolenie" }, "tab": { "user": "Používatelia", - "group": "", - "inherited": "" + "group": "Skupiny", + "inherited": "Zdedené skupiny" }, "field": { "user": { "label": "Používateľ" }, "group": { - "label": "" + "label": "Skupiny" }, "permission": { - "label": "" + "label": "Povolenia" } }, "action": { - "saveUser": "", - "saveGroup": "" + "saveUser": "Uložiť povolenie používateľa", + "saveGroup": "Uložiť povolenie skupiny" } }, "navigationStructure": { @@ -2339,30 +2657,30 @@ "label": "Dosky" }, "integrations": { - "label": "", + "label": "Integrácie", "edit": { "label": "Upraviť" }, "new": { - "label": "" + "label": "Nový" } }, "search-engines": { - "label": "", + "label": "Vyhľadávače", "new": { - "label": "" + "label": "Nový" }, "edit": { "label": "Upraviť" } }, "medias": { - "label": "" + "label": "Médiá" }, "apps": { "label": "Aplikácie", "new": { - "label": "" + "label": "Nový" }, "edit": { "label": "Upraviť" @@ -2377,7 +2695,7 @@ "security": "Bezpečnosť", "board": "Dosky", "groups": { - "label": "" + "label": "Skupiny" }, "invites": { "label": "Pozvánky" @@ -2386,9 +2704,12 @@ "tools": { "label": "Nástroje", "docker": { - "label": "" + "label": "Docker" }, "logs": { + "label": "Záznamy" + }, + "certificates": { "label": "" } }, @@ -2401,28 +2722,28 @@ } }, "search": { - "placeholder": "", - "nothingFound": "", + "placeholder": "Hľadaj čokoľvek", + "nothingFound": "Nič sa nenašlo", "error": { - "fetch": "" + "fetch": "Pri načítavaní údajov sa vyskytla chyba" }, "mode": { "appIntegrationBoard": { - "help": "", + "help": "Vyhľadajte aplikácie, integrácie alebo dosky", "group": { "app": { "title": "Aplikácie", "children": { "action": { "open": { - "label": "" + "label": "Otvoriť adresu URL aplikácie" }, "edit": { - "label": "" + "label": "Upraviť aplikáciu" } }, "detail": { - "title": "" + "title": "Vyberte akciu pre aplikáciu" } } }, @@ -2431,114 +2752,122 @@ "children": { "action": { "open": { - "label": "" + "label": "Otvoriť dosku" }, "homeBoard": { - "label": "" + "label": "Nastaviť ako domácu dosku" + }, + "mobileBoard": { + "label": "Nastaviť ako mobilnú tabuľu" }, "settings": { - "label": "" + "label": "Otvorte nastavenia" } }, "detail": { - "title": "" + "title": "Vyberte akciu pre dosku" } } }, "integration": { - "title": "" + "title": "Integrácie" } } }, "command": { - "help": "", + "help": "Aktivujte príkazový režim", "group": { "localCommand": { - "title": "" + "title": "Miestne príkazy" }, "globalCommand": { - "title": "", + "title": "Globálne príkazy", "option": { "colorScheme": { - "light": "", - "dark": "" + "light": "Prepnúť na svetlý motív", + "dark": "Prepnúť na tmavý motív" }, "language": { - "label": "", + "label": "Zmeniť jazyk", "children": { "detail": { - "title": "" + "title": "Vyberte preferovaný jazyk" } } }, "newBoard": { - "label": "" + "label": "Vytvorte novú dosku" }, "importBoard": { - "label": "" + "label": "Importujte dosku" }, "newApp": { - "label": "" + "label": "Vytvorte novú aplikáciu" }, "newIntegration": { - "label": "", + "label": "Vytvorte novú integráciu", "children": { "detail": { - "title": "" + "title": "Vyberte typ integrácie, ktorý chcete vytvoriť" } } }, "newUser": { - "label": "" + "label": "Vytvoriť nového používateľa" }, "newInvite": { - "label": "" + "label": "Vytvorenie novej pozvánky" }, "newGroup": { - "label": "" + "label": "Vytvoriť novú skupinu" } } } } }, + "media": { + "requestMovie": "Vyžiadať film", + "requestSeries": "Vyžiadať seriál", + "openIn": "Otvoriť v {kind}" + }, "external": { - "help": "", + "help": "Používanie externého vyhľadávača", "group": { "searchEngine": { - "title": "", + "title": "Vyhľadávače", "children": { "action": { "search": { - "label": "" + "label": "Hľadajte pomocou {name}" } }, "detail": { - "title": "" + "title": "Vyberte akciu pre vyhľadávací nástroj" }, "searchResults": { - "title": "" + "title": "Vyberte výsledok vyhľadávania akcií" } }, "option": { "google": { - "name": "", - "description": "" + "name": "Google", + "description": "Hľadajte na webe pomocou Google" }, "bing": { - "name": "", - "description": "" + "name": "Bing", + "description": "Vyhľadávajte na webe pomocou Bingu" }, "duckduckgo": { - "name": "", - "description": "" + "name": "DuckDuckGo", + "description": "Vyhľadávajte na webe pomocou DuckDuckGo" }, "torrent": { "name": "Torrenty", - "description": "" + "description": "Vyhľadajte torrenty na torrentdownloads.pro" }, "youTube": { - "name": "", - "description": "" + "name": "YouTube", + "description": "Hľadajte videá na YouTube" } } } @@ -2547,7 +2876,7 @@ "help": { "group": { "mode": { - "title": "" + "title": "Režimy" }, "help": { "title": "Pomocník", @@ -2556,7 +2885,7 @@ "label": "Dokumentácia" }, "submitIssue": { - "label": "" + "label": "Odoslať problém" }, "discord": { "label": "Diskord Spoločenstva" @@ -2567,64 +2896,82 @@ }, "home": { "group": { + "search": { + "title": "Hladať", + "option": { + "other": { + "label": "Hľadajte pomocou iného vyhľadávača" + }, + "no-default": { + "label": "Žiadny predvolený vyhľadávací nástroj", + "description": "Nastavte predvolený vyhľadávací nástroj v preferenciách" + }, + "search": { + "label": "Hľadať '{query}' s {name}" + }, + "from-integration": { + "description": "Ak chcete hľadať, začnite písať" + } + } + }, "local": { - "title": "" + "title": "Miestne výsledky" } } }, "page": { - "help": "", + "help": "Vyhľadávanie stránok", "group": { "page": { - "title": "", + "title": "Stránky", "option": { "manageHome": { - "label": "" + "label": "Spravovať domovskú stránku" }, "manageBoard": { - "label": "" + "label": "Spravovať dosky" }, "manageApp": { - "label": "" + "label": "Spravovať aplikácie" }, "manageIntegration": { - "label": "" + "label": "Správa integrácií" }, "manageSearchEngine": { - "label": "" + "label": "Spravujte vyhľadávače" }, "manageMedia": { - "label": "" + "label": "Spravujte médiá" }, "manageUser": { "label": "Spravovať používateľov" }, "manageInvite": { - "label": "" + "label": "Spravovať pozvánky" }, "manageGroup": { - "label": "" + "label": "Spravovať skupiny" }, "manageDocker": { - "label": "" + "label": "Spravovať docker" }, "manageApi": { - "label": "" + "label": "Swagger API" }, "manageLog": { - "label": "" + "label": "Zobraziť denníky" }, "manageTask": { - "label": "" + "label": "Spravujte úlohy" }, "manageSettings": { - "label": "" + "label": "Globálne nastavenie" }, "about": { "label": "O aplikácii" }, "homeBoard": { - "label": "" + "label": "Domáca doska" }, "preferences": { "label": "Vaše preferencie" @@ -2634,37 +2981,37 @@ } }, "userGroup": { - "help": "", + "help": "Vyhľadajte používateľov alebo skupiny", "group": { "user": { "title": "Používatelia", "children": { "action": { "detail": { - "label": "" + "label": "Zobraziť podrobnosti o používateľovi" } }, "detail": { - "title": "" + "title": "Vyberte akciu pre používateľa" } } }, "group": { - "title": "", + "title": "Skupiny", "children": { "action": { "detail": { - "label": "" + "label": "Zobraziť podrobnosti skupiny" }, "manageMember": { - "label": "" + "label": "Správa členov" }, "managePermission": { - "label": "" + "label": "Správa oprávnení" } }, "detail": { - "title": "" + "title": "Vyberte akciu pre skupinu" } } } @@ -2672,75 +3019,132 @@ } }, "engine": { - "search": "", + "search": "Nájdite vyhľadávač", "field": { "name": { "label": "Názov" }, "short": { - "label": "" + "label": "Krátky" }, "urlTemplate": { - "label": "" + "label": "Šablóna vyhľadávania URL" }, "description": { - "label": "" + "label": "Popis" } }, "page": { "list": { - "title": "", + "title": "Vyhľadávače", "noResults": { - "title": "", - "action": "" + "title": "Zatiaľ neexistujú žiadne vyhľadávače", + "action": "Vytvorte si svoj prvý vyhľadávač" }, - "interactive": "" + "interactive": "Interaktívne, používa integráciu" }, "create": { - "title": "", + "title": "Nový vyhľadávač", "notification": { "success": { - "title": "", - "message": "" + "title": "Vyhľadávač vytvorený", + "message": "Vyhľadávací nástroj bol úspešne vytvorený" }, "error": { - "title": "", - "message": "" + "title": "Vyhľadávací nástroj nie je vytvorený", + "message": "Vyhľadávací nástroj sa nepodarilo vytvoriť" } } }, "edit": { - "title": "", + "title": "Upraviť vyhľadávač", "notification": { "success": { - "title": "", - "message": "" + "title": "Zmeny boli úspešne použité", + "message": "Vyhľadávač bol úspešne uložený" }, "error": { - "title": "", - "message": "" + "title": "Nie je možné použiť zmeny", + "message": "Vyhľadávací nástroj sa nepodarilo uložiť" } }, - "configControl": "", + "configControl": "Konfigurácia", "searchEngineType": { - "generic": "", - "fromIntegration": "" + "generic": "Všeobecné", + "fromIntegration": "Z integrácie" } }, "delete": { - "title": "", - "message": "", + "title": "Odstrániť vyhľadávací nástroj", + "message": "Ste si istí, že chcete odstrániť vyhľadávač '{name}'?", "notification": { "success": { - "title": "", - "message": "" + "title": "Vyhľadávač odstránený", + "message": "Vyhľadávací nástroj bol úspešne odstránený" }, "error": { - "title": "", - "message": "" + "title": "Vyhľadávač nebol odstránený", + "message": "Vyhľadávací nástroj sa nepodarilo odstrániť" } } } + }, + "media": { + "request": { + "modal": { + "title": "Vyžiadať \"{name}\"", + "table": { + "header": { + "season": "Séria", + "episodes": "Epizódy" + } + }, + "button": { + "send": "Poslať požiadavku" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/sl.json b/packages/translation/src/lang/sl.json index b16c4c6b3..2767a297c 100644 --- a/packages/translation/src/lang/sl.json +++ b/packages/translation/src/lang/sl.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "Aplikacije", + "boards": "Deske", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "Žeton", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "Nastavitve", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "Uporabniki", "name": "Uporabnik", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "Aplikacije", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "Aplikacije", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "Prejšnji", "next": "Naslednji", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Poskusite znova", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Prijava", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Nevarno območje", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -908,13 +1043,13 @@ "label": "" }, "layout": { - "label": "", + "label": "Postavitev", "option": { "row": { - "label": "" + "label": "Vodoravno" }, "column": { - "label": "" + "label": "Navpično" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Blokirano danes", "dnsQueriesToday": "Poizvedbe danes", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Beležnica", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Vaš brskalnik ne podpira iframov. Posodobite svoj brskalnik." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "", + "queue": "Čakalna vrsta", + "statistics": "" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "", + "status": { + "healthy": "", + "unhealthy": "" + } + }, + "panel": { + "statistics": { + "empty": "Prazno", + "transcodes": "", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "" + }, + "workers": { + "empty": "Prazno", + "table": { + "file": "", + "eta": "", + "progress": "Napredek", + "transcode": "", + "healthCheck": "" + } + }, + "queue": { + "empty": "Prazno", + "table": { + "file": "", + "size": "Velikost", + "transcode": "", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Majhna", "md": "Srednja", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Trajno izbriši", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Splošno", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Prvi dan v tednu", "accessibility": "Dostopnost" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Splošno", - "owner": "", + "owner": "Lastnik", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Deske", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Videz", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Napaka" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/sv.json b/packages/translation/src/lang/sv.json index 33e56d1fd..fc5338049 100644 --- a/packages/translation/src/lang/sv.json +++ b/packages/translation/src/lang/sv.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "Appar", + "boards": "Tavlor", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "Inställningar", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "Användare", "name": "Användare", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "Appar", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "Appar", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "Föregående", "next": "Nästa", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Försök igen", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Logga in", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Farozon", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -911,10 +1046,10 @@ "label": "", "option": { "row": { - "label": "" + "label": "Horisontal" }, "column": { - "label": "" + "label": "Vertikal" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Blockerade idag", "dnsQueriesToday": "Förfrågningar idag", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Anteckningsbok", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Din webbläsare stöder inte iframes. Vänligen uppdatera din webbläsare." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "Standardvy" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "Arbetare", + "queue": "Kö", + "statistics": "Statistik" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "Köad", + "status": { + "healthy": "Hälsosam", + "unhealthy": "Ohälsosam" + } + }, + "panel": { + "statistics": { + "empty": "Tom", + "transcodes": "Omkodning", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "Upplösningar" + }, + "workers": { + "empty": "Tom", + "table": { + "file": "Fil", + "eta": "Beräknad sluttid", + "progress": "Förlopp", + "transcode": "Omkoda", + "healthCheck": "" + } + }, + "queue": { + "empty": "Tom", + "table": { + "file": "Fil", + "size": "Storlek", + "transcode": "Omkoda", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Liten", "md": "Mellan", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Radera permanent", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Allmänt", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Första veckodagen", "accessibility": "Tillgänglighet" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Allmänt", - "owner": "", + "owner": "Ägare", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Tavlor", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Utseende", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Fel" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/tr.json b/packages/translation/src/lang/tr.json index 00f73dab9..800e7a5a2 100644 --- a/packages/translation/src/lang/tr.json +++ b/packages/translation/src/lang/tr.json @@ -1,26 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "Homarr'a Hoş Geldiniz", + "subtitle": "Homarr örneğinizi kurmaya başlayalım.", + "description": "Başlamak için lütfen Homarr örneğinizi nasıl kurmak istediğinizi seçin.", + "action": { + "scratch": "Sıfırdan Başla", + "importOldmarr": "Homarr 1.0'dan Önceki Yedeğinizi İçe Aktarın" + } + }, + "import": { + "title": "Verileri İçe Aktar", + "subtitle": "Mevcut Homarr Örneğinden Alınan Verileri İçe Aktarabilirsiniz.", + "dropzone": { + "title": "Zip dosyasını buraya sürükleyin veya göz atmak için tıklayın", + "description": "Seçtiğiniz zip işlenecek ve içe aktarmak istediğiniz verileri seçebileceksiniz" + }, + "fileInfo": { + "action": { + "change": "Dosyayı Değiştir" + } + }, + "importSettings": { + "title": "İçe Aktarma Ayarları", + "description": "İçe Aktarma İşlevlerini Yapılandırın" + }, + "boardSelection": { + "title": "{count} Panel Bulundu", + "description": "İçe Aktarılacak Tüm Panellerin Boyutlarını Seçin", + "action": { + "selectAll": "Tümünü Seç", + "unselectAll": "Tüm Seçimi Kaldır" + } + }, + "summary": { + "title": "İçe Aktarma Özeti", + "description": "Aşağıdaki Özeti Kontrol Ederek İçe Aktarılacak İşlevleri Görebilirsiniz", + "action": { + "import": "İçe Aktarmayı Onayla ve Devam Et" + }, + "entities": { + "apps": "Uygulamalar", + "boards": "Paneller", + "integrations": "Entegrasyonlar", + "credentialUsers": "Kullanıcı Kimlik Bilgileri" + } + }, + "tokenModal": { + "title": "İçe Aktarma Token'ını Girin", + "field": { + "token": { + "label": "Token", + "description": "Önceki Homarr Örneğinizden Aldığınız İçe Aktarma Token'ını girin" + } + }, + "notification": { + "error": { + "title": "Token", + "message": "Girdiğiniz Token Geçersiz" + } + } + } + }, + "user": { + "title": "Yönetici", + "subtitle": "Yönetici kullanıcınız için kimlik bilgilerini girin.", + "notification": { + "success": { + "title": "Kullanıcı oluşturuldu", + "message": "Kullanıcı başarıyla oluşturuldu" + }, + "error": { + "title": "Kullanıcı oluşturma başarısız oldu" + } + } + }, + "group": { + "title": "Dış grup", + "subtitle": "Harici kullanıcılar için kullanılacak grubu belirtin.", + "form": { + "name": { + "label": "Grup adı", + "description": "Ad, harici sağlayıcının yönetici grubuyla eşleşmelidir" + } + } + }, + "settings": { + "title": "Ayarlar", + "subtitle": "Sunucu ayarlarınızı yapılandırın." + }, + "finish": { + "title": "Kurulumu Bitir", + "subtitle": "Başlamaya Hazırsınız!", + "description": "Kurulum sürecini başarıyla tamamladınız. Artık Homarr'ı kullanmaya başlayabilirsiniz. Sonraki eyleminizi seçin:", + "action": { + "goToBoard": "{name} Paneline Git", + "createBoard": "İlk Panelinizi Oluşturun", + "inviteUser": "Yeni Kullanıcı Davet Et", + "docs": "Dökümanları Oku" + } + } + }, + "backToStart": "Başlangıca Geri Dön" + }, "user": { "title": "Kullanıcılar", "name": "Kullanıcı", "page": { "login": { - "title": "", - "subtitle": "" + "title": "Hesabınıza Giriş Yapın", + "subtitle": "Tekrar hoş geldiniz! Lütfen kimlik bilgilerinizi girin" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "Homarr'a Katıl", + "subtitle": "Homarr'a hoş geldiniz! Lütfen hesabınızı oluşturun", + "description": "{username} tarafından davet edildiniz" }, "init": { - "title": "", - "subtitle": "" + "title": "Yeni Homarr Kurulumu", + "subtitle": "Lütfen yönetici kullanıcısını oluşturun" } }, "field": { "email": { "label": "E-Posta", - "verified": "" + "verified": "Doğrulandı" }, "username": { "label": "Kullanıcı adı" @@ -28,46 +133,46 @@ "password": { "label": "Şifre", "requirement": { - "length": "", + "length": "En az 8 karakter içermeli", "lowercase": "Küçük harf içermeli", "uppercase": "Büyük harf içermeli", "number": "Rakam içermeli", - "special": "" + "special": "Özel sembol içermeli" } }, "passwordConfirm": { - "label": "Şifreyi onayla" + "label": "Şifreyi Onayla" }, "previousPassword": { - "label": "" + "label": "Eski Şifre" }, "homeBoard": { - "label": "" + "label": "Ana panel" }, "pingIconsEnabled": { - "label": "" + "label": "Pingler İçin Simgeler Kullanın" } }, "error": { - "usernameTaken": "" + "usernameTaken": "Kullanıcı Adı Önceden Alındı" }, "action": { "login": { "label": "Giriş", - "labelWith": "", + "labelWith": "{provider} ile giriş yapın", "notification": { "success": { - "title": "", - "message": "" + "title": "Giriş başarılı", + "message": "Şu anda giriş yaptınız" }, "error": { - "title": "", - "message": "" + "title": "Giriş başarısız", + "message": "Girişiniz başarısız oldu" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "Şifrenizi mi unuttunuz?", + "description": "Yöneticiniz parolanızı sıfırlamak için aşağıdaki komutu kullanabilir:" } }, "register": { @@ -75,81 +180,91 @@ "notification": { "success": { "title": "Hesap oluşturuldu", - "message": "" + "message": "Devam etmek için lütfen giriş yapın" }, "error": { - "title": "", - "message": "" + "title": "Hesap oluşturma başarısız oldu", + "message": "Hesabınız oluşturulamadı" } } }, "create": "Kullanıcı ekle", "changePassword": { - "label": "", + "label": "Parolayı değiştir", "notification": { "success": { - "message": "" + "message": "Parola başarıyla değiştirildi" }, "error": { - "message": "" + "message": "Parola değiştirilemedi" } } }, "changeHomeBoard": { "notification": { "success": { - "message": "" + "message": "Öntanımlı panel başarıyla değiştirildi" }, "error": { - "message": "" + "message": "Öntanımlı panel değiştirilemiyor" + } + } + }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "Öntanımlı arama motoru başarıyla değiştirildi" + }, + "error": { + "message": "Öntanımlı arama motoru değiştirilemiyor" } } }, "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "Haftanın ilk günü başarıyla değiştirildi" }, "error": { - "message": "" + "message": "Haftanın ilk günü değiştirilemiyor" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "Ping simgeleri başarıyla değiştirildi" }, "error": { - "message": "" + "message": "Ping simgeleri değiştirilemiyor" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Görseli değiştir", "notification": { "success": { - "message": "" + "message": "Görsel başarıyla değiştirildi" }, "error": { - "message": "" + "message": "Görsel değiştirilemiyor" }, "toLarge": { - "title": "", - "message": "" + "title": "Görsel çok büyük", + "message": "Maksimum görsel boyutu {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Görseli kaldır", + "confirm": "Görseli kaldırmak istediğinizden emin misiniz?", "notification": { "success": { - "message": "" + "message": "Görsel başarıyla kaldırıldı" }, "error": { - "message": "" + "message": "Görsel kaldırılamıyor" } } } @@ -157,63 +272,63 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "Profil başarıyla güncellendi" }, "error": { - "message": "" + "message": "Profil güncellenemiyor" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "Kullanıcıyı kalıcı olarak sil", + "description": "Bu kullanıcıyı tercihleriyle birlikte siler. Hiçbir panel silinmeyecektir. Kullanıcı bilgilendirilmez.", + "confirm": "{username} kullanıcısını tercihleriyle birlikte silmek istediğinizden emin misiniz?" }, "select": { - "label": "", - "notFound": "" + "label": "Kullanıcıyı seç", + "notFound": "Kullanıcı bulunmadı" }, "transfer": { - "label": "" + "label": "Yeni sahibi seç" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "Gruplar", + "name": "Grup", + "search": "Grup bul", "field": { "name": "İsim", - "members": "" + "members": "Üyeler" }, "permission": { "admin": { "title": "Yönetici", "item": { "admin": { - "label": "", - "description": "" + "label": "Yönetici", + "description": "Bu izne sahip üyeler tüm özelliklere ve ayarlara tam erişime sahiptir" } } }, "app": { - "title": "", + "title": "Uygulamalar", "item": { "create": { - "label": "", - "description": "" + "label": "Uygulamalar oluşturun", + "description": "Üyelerin uygulama oluşturmasına izin ver" }, "use-all": { - "label": "", - "description": "" + "label": "Tüm uygulamaları kullan", + "description": "Üyelerin panellere herhangi bir uygulama eklemelerine izin ver" }, "modify-all": { - "label": "", - "description": "" + "label": "Tüm uygulamaları değiştir", + "description": "Üyelerin tüm uygulamaları değiştirmesine izin ver" }, "full-all": { - "label": "", - "description": "" + "label": "Uygulamaya tam erişim", + "description": "Üyelerin herhangi bir uygulamayı yönetmesine, kullanmasına ve silmesine izin ver" } } }, @@ -221,214 +336,215 @@ "title": "Paneller", "item": { "create": { - "label": "", - "description": "" + "label": "Panel oluştur", + "description": "Üyelerin panel oluşturmasına izin ver" }, "view-all": { - "label": "", - "description": "" + "label": "Tüm panelleri görüntüle", + "description": "Üyelerin tüm panelleri görüntülemesine izin ver" }, "modify-all": { - "label": "", - "description": "" + "label": "Tüm panelleri değiştir", + "description": "Üyelerin tüm panelleri değiştirmesine izin ver (Erişim kontrolü ve tehlikeli alan dahil değildir)" }, "full-all": { - "label": "", - "description": "" + "label": "Tam panel erişimi", + "description": "Üyelerin tüm panelleri görüntülemesine, değiştirmesine ve silmesine izin verin (Erişim kontrolü ve tehlikeli alan dahil)" } } }, "integration": { - "title": "", + "title": "Entegrasyonlar", "item": { "create": { - "label": "", - "description": "" + "label": "Entegrasyonlar oluştur", + "description": "Üyelerin entegrasyonlar oluşturmasına izin ver" }, "use-all": { - "label": "", - "description": "" + "label": "Tüm entegrasyonları kullan", + "description": "Üyelerin panellere herhangi bir entegrasyonu eklemelerine olanak tanır" }, "interact-all": { - "label": "", - "description": "" + "label": "Herhangi bir entegrasyonla etkileşim kurun", + "description": "Üyelerin herhangi bir entegrasyonla etkileşime girmesine izin verin" }, "full-all": { - "label": "", - "description": "" + "label": "Tam entegrasyon erişimi", + "description": "Üyelerin herhangi bir entegrasyonu yönetmesine, kullanmasına ve etkileşimde bulunmasına izin ver" } } }, "media": { - "title": "", + "title": "Medyalar", "item": { "upload": { - "label": "", - "description": "" + "label": "Medya yükle", + "description": "Üyelerin medya yüklemesine izin ver" }, "view-all": { - "label": "", - "description": "" + "label": "Tüm medyayı görüntüle", + "description": "Üyelerin tüm medyayı görüntülemesine izin ver" }, "full-all": { - "label": "", - "description": "" + "label": "Tam medya erişimi", + "description": "Üyelerin herhangi bir medyayı yönetmesine ve silmesine izin ver" } } }, "other": { - "title": "", + "title": "Diğer", "item": { "view-logs": { - "label": "", - "description": "" + "label": "Günlükleri görüntüle", + "description": "Üyelerin günlükleri görüntülemesine izin ver" } } }, "search-engine": { - "title": "", + "title": "Arama Motorları", "item": { "create": { - "label": "", - "description": "" + "label": "Arama motorları oluşturun", + "description": "Üyelerin arama motorları oluşturmasına izin ver" }, "modify-all": { - "label": "", - "description": "" + "label": "Tüm arama motorlarını değiştir", + "description": "Üyelerin tüm arama motorlarını değiştirmesine izin ver" }, "full-all": { - "label": "", - "description": "" + "label": "Tam arama motoru erişimi", + "description": "Üyelerin herhangi bir arama motorunu yönetmesine ve silmesine izin ver" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "Bazı üyeler harici sağlayıcılardandır ve burada yönetilemezler", + "external": "Tüm üyeler harici sağlayıcılardandır ve burada yönetilemezler" }, "reservedNotice": { - "message": "" + "message": "Bu grup sistem kullanımı için ayrılmıştır ve bazı eylemleri kısıtlar. " }, "action": { "create": { - "label": "", + "label": "Yeni grup", "notification": { "success": { - "message": "" + "message": "Grup başarıyla oluşturuldu" }, "error": { - "message": "" + "message": "Grup oluşturulamadı" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "Sahipliği aktar", + "description": "Bu grubun sahipliğini başka bir kullanıcıya aktarın.", + "confirm": "{name} grubunun mülkiyetini {username} grubuna devretmek istediğinizden emin misiniz?", "notification": { "success": { - "message": "" + "message": "{group} grubu başarıyla {user} grubuna aktarıldı" }, "error": { - "message": "" + "message": "Sahiplik aktarımı yapılamıyor" } } }, "addMember": { - "label": "" + "label": "Üye ekle" }, "removeMember": { - "label": "", - "confirm": "" + "label": "Üyeyi kaldır", + "confirm": "{user} adlı kişiyi bu gruptan kaldırmak istediğinizden emin misiniz?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "Grubu sil", + "description": "Bir grubu sildiğinizde geri dönüş yoktur. Lütfen emin olun.", + "confirm": "{name} grubunu silmek istediğinizden emin misiniz?", "notification": { "success": { - "message": "" + "message": "{name} grubu başarıyla silindi" }, "error": { - "message": "" + "message": "{name} grubu silinemiyor" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "İzinler kaydedildi", + "message": "İzinler başarıyla kaydedildi" }, "error": { - "title": "", - "message": "" + "title": "İzinler kaydedilmedi", + "message": "İzinler kaydedilmedi" } } }, "update": { "notification": { "success": { - "message": "" + "message": "{name} grubu başarıyla kaydedildi" }, "error": { - "message": "" + "message": "Grup kaydedilemiyor {name}" } } }, "select": { - "label": "", - "notFound": "" + "label": "Grup Seç", + "notFound": "Grup bulunamadı" } } }, "app": { + "search": "Uygulama Bulun", "page": { "list": { "title": "Uygulamalar", "noResults": { - "title": "", - "action": "" + "title": "Henüz uygulama oluşturulmadı", + "action": "İlk uygulamanızı oluşturun" } }, "create": { - "title": "", + "title": "Yeni Uygulama", "notification": { "success": { - "title": "", - "message": "" + "title": "Oluşturma başarılı", + "message": "Uygulama başarıyla oluşturuldu" }, "error": { - "title": "", - "message": "" + "title": "Oluşturma başarısız oldu", + "message": "Uygulama oluşturulamadı" } } }, "edit": { - "title": "", + "title": "Uygulamayı düzenle", "notification": { "success": { - "title": "", - "message": "" + "title": "Değişiklikler başarıyla uygulandı", + "message": "Uygulama başarıyla kaydedildi" }, "error": { - "title": "", - "message": "" + "title": "Değişiklikler uygulanamıyor", + "message": "Uygulama kaydedilemedi" } } }, "delete": { - "title": "", - "message": "", + "title": "Uygulamayı sil", + "message": "{name} uygulamasını silmek istediğinizden emin misiniz?", "notification": { "success": { - "title": "", - "message": "" + "title": "Silme başarılı", + "message": "Uygulama başarıyla silindi" }, "error": { - "title": "", - "message": "" + "title": "Silme başarısız oldu", + "message": "Uygulama silinemiyor" } } } @@ -438,65 +554,65 @@ "label": "İsim" }, "description": { - "label": "" + "label": "Tanım" }, "url": { - "label": "" + "label": "Url" } }, "action": { "select": { - "label": "", - "notFound": "" + "label": "Uygulama seç", + "notFound": "Uygulama bulunamadı" } } }, "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "Entegrasyonlar", + "search": "Entegrasyon ara", "noResults": { - "title": "" + "title": "Henüz entegrasyon yok" } }, "create": { - "title": "", + "title": "Yeni {name} Entegrasyonu", "notification": { "success": { - "title": "", - "message": "" + "title": "Oluşturma başarılı", + "message": "Entegrasyon başarıyla oluşturuldu" }, "error": { - "title": "", - "message": "" + "title": "Oluşturma başarısız oldu", + "message": "Entegrasyon oluşturulamadı" } } }, "edit": { - "title": "", + "title": "{name} entegrasyonu düzenle", "notification": { "success": { - "title": "", - "message": "" + "title": "Değişiklikler başarıyla uygulandı", + "message": "Entegrasyon başarıyla kaydedildi" }, "error": { - "title": "", - "message": "" + "title": "Değişiklikler uygulanamıyor", + "message": "Entegrasyon kaydedilemedi" } } }, "delete": { - "title": "", - "message": "", + "title": "Entegrasyonu Sil", + "message": "{name} entegrasyonunu silmek istediğinizden emin misiniz?", "notification": { "success": { - "title": "", - "message": "" + "title": "Silme başarılı", + "message": "Entegrasyon başarıyla silindi" }, "error": { - "title": "", - "message": "" + "title": "Silme başarısız oldu", + "message": "Entegrasyon silinemiyor" } } } @@ -506,121 +622,129 @@ "label": "İsim" }, "url": { - "label": "" + "label": "Url" + }, + "attemptSearchEngineCreation": { + "label": "Arama Motoru Oluştur", + "description": "\"{kind}\" entegrasyonu arama motorlarıyla kullanılabilir. Arama motorunu otomatik olarak yapılandırmak için bunu işaretleyin." } }, "action": { - "create": "" + "create": "Yeni Entegrasyon" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "Bağlantıyı test et ve oluştur", + "edit": "Bağlantıyı test et ve kaydet" }, - "alertNotice": "", + "alertNotice": "Bağlantı kurulumu başaralı olduğunda Kaydet düğmesi etkinleştirilir", "notification": { "success": { - "title": "", - "message": "" + "title": "Bağlantı başarılı", + "message": "Bağlantı başarıyla kuruldu" }, "invalidUrl": { "title": "Geçersiz URL", - "message": "" + "message": "URL geçersiz" }, "secretNotDefined": { - "title": "", - "message": "" + "title": "Eksik kimlik bilgileri", + "message": "Tüm kimlik bilgileri sağlanmadı" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "Geçersiz kimlik bilgileri", + "message": "Kimlik bilgileri geçersiz" }, "commonError": { - "title": "", - "message": "" + "title": "Bağlantı başarısız oldu", + "message": "Bağlantı kurulamadı" }, "badRequest": { - "title": "", - "message": "" + "title": "Geçersiz istek", + "message": "Talep hatalı biçimlendirilmiş" }, "unauthorized": { - "title": "", - "message": "" + "title": "Yetkisiz", + "message": "Muhtemelen yanlış kimlik bilgileri" }, "forbidden": { - "title": "", - "message": "" + "title": "Yasaklı", + "message": "Muhtemelen izinler eksik" }, "notFound": { - "title": "", - "message": "" + "title": "Bulunamadı", + "message": "Muhtemelen yanlış Url veya yol" }, "internalServerError": { - "title": "", - "message": "" + "title": "İç Sunucu Hatası", + "message": "Sunucu bir hatayla karşılaştı" }, "serviceUnavailable": { - "title": "", - "message": "" + "title": "Hizmet kullanılamıyor", + "message": "Sunucu şu anda kullanılamıyor" }, "connectionAborted": { - "title": "", - "message": "" + "title": "Bağlantı kesildi", + "message": "Bağlantı iptal edildi" }, "domainNotFound": { - "title": "", - "message": "" + "title": "Alan adı bulunamadı", + "message": "Alan adı bulunamadı" }, "connectionRefused": { - "title": "", - "message": "" + "title": "Bağlantı rededildi", + "message": "Bağlantı reddedildi" }, "invalidJson": { - "title": "", - "message": "" + "title": "Geçersiz JSON", + "message": "Yanıt geçerli bir JSON değildi" }, "wrongPath": { - "title": "", - "message": "" + "title": "Yanlış yol", + "message": "Yol muhtemelen doğru değil" } } }, "secrets": { - "title": "", - "lastUpdated": "", - "secureNotice": "", + "title": "Gizli anahtarlar", + "lastUpdated": "Son güncelleme {date}", + "notSet": { + "label": "Değer ayarlanmadı", + "tooltip": "Gizli anahtar gereklidir ve henüz ayarlanmadı" + }, + "secureNotice": "Bu Gizli anahtar oluşturulduktan sonra geri alınamaz", "reset": { - "title": "", - "message": "" + "title": "Gizli anahtarı sıfırla", + "message": "Gizli anahtarı sıfırlamak istediğinizden emin misiniz?" }, "noSecretsRequired": { - "segmentTitle": "", - "text": "" + "segmentTitle": "Gizli Anahtar Yok", + "text": "Bu entegrasyon için gizli anahtar gerekmiyor" }, "kind": { "username": { "label": "Kullanıcı adı", - "newLabel": "" + "newLabel": "Yeni Kullanıcı Adı" }, "apiKey": { - "label": "", - "newLabel": "" + "label": "API Anahtarı", + "newLabel": "Yeni API Anahtarı" }, "password": { "label": "Şifre", - "newLabel": "Yeni parola" + "newLabel": "Yeni Şifre" } } }, "permission": { - "use": "", - "interact": "", - "full": "" + "use": "Öğelerdeki entegrasyonları seçin", + "interact": "Entegrasyonlarla etkileşim kurun", + "full": "Tam entegrasyon erişimi" } }, "media": { - "plural": "", - "search": "", + "plural": "Medyalar", + "search": "Bir medya bul", "field": { "name": "İsim", "size": "Boyut", @@ -628,145 +752,155 @@ }, "action": { "upload": { - "label": "", - "file": "", + "label": "Medya yükle", + "file": "Dosya seç", "notification": { "success": { - "message": "" + "message": "Medya başarıyla yüklendi" }, "error": { - "message": "" + "message": "Medya yüklenemedi" } } }, "delete": { - "label": "", - "description": "", + "label": "Medyayı sil", + "description": "medyasını silmek istediğinizden emin misiniz?", "notification": { "success": { - "message": "" + "message": "Medya başarıyla silindi" }, "error": { - "message": "" + "message": "Medya silinemedi" } } }, "copy": { - "label": "" + "label": "URL'yi kopyala" } } }, "common": { - "beta": "", + "beta": "Test", "error": "Hata", "action": { "add": "Ekle", "apply": "Uygula", - "backToOverview": "", + "backToOverview": "Genel bakışa dön", "create": "Oluştur", "edit": "Düzenle", - "import": "", + "import": "İçe aktar", "insert": "Ekle", "remove": "Kaldır", "save": "Kaydet", "saveChanges": "Değişiklikleri kaydet", "cancel": "Vazgeç", "delete": "Sil", - "discard": "", + "discard": "Yoksay", "confirm": "Onayla", - "continue": "", + "continue": "Devam Et", "previous": "Önceki", "next": "İleri", - "checkoutDocs": "", + "checkoutDocs": "Dökümanlara göz atın", + "checkLogs": "Daha fazla ayrıntı için günlükleri kontrol edin", "tryAgain": "Tekrar Deneyin", - "loading": "" + "loading": "Yükleniyor" }, - "here": "", + "here": "buraya", "iconPicker": { - "label": "", - "header": "" + "label": "Simge URL'si", + "header": "Simgeleri filtrelemek için isim veya nesne yazın... Homarr sizin için {countIcons} simge arasında arama yapacaktır." + }, + "colorScheme": { + "options": { + "light": "Aydınlık", + "dark": "Koyu" + } }, "information": { - "min": "", - "max": "", - "days": "", + "min": "En Düşük", + "max": "En Yüksek", + "days": "Gün", "hours": "Saat", "minutes": "Dakika" }, "notification": { "create": { - "success": "", - "error": "" + "success": "Oluşturma başarılı", + "error": "Oluşturma başarısız oldu" }, "delete": { - "success": "", - "error": "" + "success": "Silme başarılı", + "error": "Silme başarısız oldu" }, "update": { - "success": "", - "error": "" + "success": "Değişiklikler başarıyla uygulandı", + "error": "Değişiklikler uygulanamıyor" }, "transfer": { - "success": "", - "error": "" + "success": "Transfer başarılı", + "error": "Transfer başarısız" } }, "multiSelect": { - "placeholder": "" + "placeholder": "Bir veya daha fazla değer seçin" }, "multiText": { - "placeholder": "", - "addLabel": "" + "placeholder": "Daha fazla değer ekleyin", + "addLabel": "{value} ekle" }, "select": { - "placeholder": "", + "placeholder": "Değer seç", "badge": { - "recommended": "" + "recommended": "Tavsiye edilen" } }, "userAvatar": { "menu": { - "switchToDarkMode": "", - "switchToLightMode": "", - "management": "", + "switchToDarkMode": "Koyu Temaya Geç", + "switchToLightMode": "Aydınlık Temaya Geç", + "management": "Yönetim", "preferences": "Tercihleriniz", - "logout": "", + "logout": "Oturumu kapat", "login": "Giriş", - "homeBoard": "", - "loggedOut": "" + "homeBoard": "Öntanımlı Panel", + "loggedOut": "Oturum kapatıldı", + "updateAvailable": "{countUpdates} güncelleme mevcut: {tag}" } }, - "dangerZone": "Tehlikeli bölge", + "dangerZone": "Tehlikeli Bölge", "noResults": "Sonuç bulunamadı", "preview": { - "show": "", - "hide": "" + "show": "Ara Renkleri Göster", + "hide": "Ara Renkleri Gizle" }, "zod": { "errors": { "default": "Bu alan geçersiz", - "required": "Bu alan gereklidir", + "required": "Bu alan gerekli", "string": { "startsWith": "Bu alan {startsWith} ile başlamalıdır", "endsWith": "Bu alan {endsWith} ile bitmelidir", - "includes": "Bu alan {includes} adresini içermelidir", - "invalidEmail": "" + "includes": "Bu alan {includes} içermelidir", + "invalidEmail": "Bu alanda geçerli bir e-posta olmalıdır" }, "tooSmall": { "string": "Bu alan en az {minimum} karakter uzunluğunda olmalıdır", - "number": "Bu alan {minimum} adresinden uzun veya eşit olmalıdır" + "number": "Bu alan {minimum} değerinden uzun veya eşit olmalıdır" }, "tooBig": { "string": "Bu alan en fazla {maximum} karakter uzunluğunda olmalıdır", - "number": "Bu alan {maximum} adresinden kısa veya eşit olmalıdır" + "number": "Bu alan {maximum} değerinden kısa veya eşit olmalıdır" }, "custom": { - "passwordsDoNotMatch": "", - "passwordRequirements": "", - "boardAlreadyExists": "", - "invalidFileType": "", - "fileTooLarge": "", - "invalidConfiguration": "" + "passwordsDoNotMatch": "Parolalar uyuşmuyor", + "passwordRequirements": "Parola gereksinimleri karşılamıyor", + "boardAlreadyExists": "Bu isimde bir panel zaten mevcut", + "invalidFileType": "Geçersiz dosya türü, {expected} bekleniyor", + "invalidFileName": "", + "fileTooLarge": "Dosya çok büyük, azami boyut {maxSize}", + "invalidConfiguration": "Geçersiz yapılandırma", + "groupNameTaken": "Grup adı zaten alınmış" } } } @@ -774,12 +908,12 @@ "section": { "dynamic": { "action": { - "create": "", - "remove": "" + "create": "Yeni Dinamik Bölüm", + "remove": "Dinamik bölümü kaldır" }, "remove": { - "title": "", - "message": "" + "title": "Dinamik bölümü kaldır", + "message": "Bu dinamik bölümü kaldırmak istediğinizden emin misiniz? Öğeler üst bölümdeki aynı konuma taşınacaktır." } }, "category": { @@ -789,29 +923,29 @@ } }, "action": { - "create": "", - "edit": "", - "remove": "", + "create": "Yeni Kategori", + "edit": "Kategoriyi Yeniden Adlandır", + "remove": "Kategoriyi kaldır", "moveUp": "Yukarı taşı", "moveDown": "Aşağı taşı", - "createAbove": "", - "createBelow": "" + "createAbove": "Yukarı Yeni Kategori", + "createBelow": "Aşağı Yeni Kategori" }, "create": { - "title": "", - "submit": "" + "title": "Yeni Kategori", + "submit": "Kategori ekle" }, "remove": { - "title": "", - "message": "" + "title": "Kategoriyi kaldır", + "message": "{name} kategorisini kaldırmak istediğinizden emin misiniz?" }, "edit": { - "title": "", - "submit": "" + "title": "Kategoriyi Yeniden Adlandır", + "submit": "Kategoriyi Yeniden Adlandır" }, "menu": { "label": { - "create": "", + "create": "Yeni Kategori", "changePosition": "Pozisyonu değiştir" } } @@ -819,12 +953,12 @@ }, "item": { "action": { - "create": "", - "import": "", - "edit": "", - "moveResize": "", - "duplicate": "", - "remove": "" + "create": "Yeni Öğe", + "import": "Öğeleri İçe Aktar", + "edit": "Öğeyi Düzenle", + "moveResize": "Öğeyi Taşı / Yeniden Boyutlandır", + "duplicate": "Öğeyi Çoğalt", + "remove": "Öğeyi kaldır" }, "menu": { "label": { @@ -832,11 +966,12 @@ } }, "create": { - "title": "", - "addToBoard": "" + "title": "Eklenecek öğeyi seçin", + "search": "Öğeleri Filtrele", + "addToBoard": "Panele Ekle" }, "moveResize": { - "title": "", + "title": "Öğeyi Taşı / Yeniden Boyutlandır", "field": { "width": { "label": "Genişlik" @@ -845,91 +980,91 @@ "label": "Yükseklik" }, "xOffset": { - "label": "" + "label": "X Ekseni" }, "yOffset": { - "label": "" + "label": "Y Ekseni" } } }, "edit": { - "title": "", + "title": "Öğeyi Düzenle", "advancedOptions": { - "label": "", - "title": "" + "label": "Gelişmiş seçenekler", + "title": "Gelişmiş öğe seçenekleri" }, "field": { "integrations": { - "label": "" + "label": "Entegrasyonlar" }, "customCssClasses": { - "label": "" + "label": "Özel CSS Alanı" } } }, "remove": { - "title": "", - "message": "" + "title": "Öğeyi kaldır", + "message": "Bu öğeyi kaldırmak istediğinizden emin misiniz?" } }, "widget": { "app": { - "name": "", - "description": "", + "name": "Uygulama", + "description": "Panelin içine uygulama yerleştirir.", "option": { "appId": { - "label": "" + "label": "Uygulama seç" }, "openInNewTab": { - "label": "Yeni sekmede aç" + "label": "Yeni Sekmede Aç" }, "showTitle": { - "label": "" + "label": "Uygulama adını göster" }, "showDescriptionTooltip": { - "label": "" + "label": "Açıklama ipucunu göster" }, "pingEnabled": { - "label": "" + "label": "Basit ping'i etkinleştir" } }, "error": { "notFound": { - "label": "", - "tooltip": "" + "label": "Uygulama Eklenmedi", + "tooltip": "Geçerli bir uygulama seçmediniz" } } }, "bookmarks": { - "name": "", - "description": "", + "name": "Yer İmleri", + "description": "Birden fazla uygulama bağlantısını görüntüler", "option": { "title": { - "label": "" + "label": "Başlık" }, "layout": { - "label": "", + "label": "Düzen", "option": { "row": { - "label": "" + "label": "Yatay" }, "column": { - "label": "" + "label": "Dikey" }, "grid": { - "label": "" + "label": "Izgara" } } }, "items": { - "label": "", - "add": "" + "label": "Yer İmleri", + "add": "Yer imi ekle" } } }, "dnsHoleSummary": { - "name": "", - "description": "", + "name": "DNS Çözümleyici Özeti", + "description": "DNS Çözümleyici özetini görüntüler", "option": { "layout": { "label": "Düzen", @@ -941,27 +1076,28 @@ "label": "Dikey" }, "grid": { - "label": "" + "label": "Izgara" } } }, "usePiHoleColors": { - "label": "" + "label": "Pi-Hole renklerini kullan" } }, "error": { - "internalServerError": "", - "integrationsDisconnected": "" + "internalServerError": "DNS Çözümleyici Özeti alınamadı", + "integrationsDisconnected": "Veri Bulunamadı, Tüm Entegrasyonların Bağlantısı Kesildi" }, "data": { "adsBlockedToday": "Bugün engellenenler", "adsBlockedTodayPercentage": "Bugün engellenenler", "dnsQueriesToday": "Bugünkü Sorgular", - "domainsBeingBlocked": "" - } + "domainsBeingBlocked": "Engelleme listesindeki alan adları" + }, + "domainsTooltip": "Birden fazla entegrasyon nedeniyle Homarr, engellenen alan adlarının tam sayısını hesaplayamıyor" }, "dnsHoleControls": { - "name": "", + "name": "DNS Çözümleyici Kontrolleri", "description": "Kontrol panelinizden PiHole veya AdGuard'ı kontrol edin", "option": { "layout": { @@ -974,68 +1110,87 @@ "label": "Dikey" }, "grid": { - "label": "" + "label": "Izgara" } } }, "showToggleAllButtons": { - "label": "" + "label": "Tüm Geçiş Yap Düğmelerini Göster" } }, "error": { - "internalServerError": "" + "internalServerError": "DNS Çözümleyici kontrol edilemedi" }, "controls": { - "enableAll": "", - "disableAll": "", - "setTimer": "", + "enableAll": "Tümünü Etkinleştir", + "disableAll": "Tümünü Devre Dışı Bırak", + "setTimer": "Zamanlayıcıyı Ayarla", "set": "Ayarla", "enabled": "Etkin", "disabled": "Pasif", - "processing": "", - "disconnected": "", + "processing": "İşlemde", + "disconnected": "Bağlantısı kesildi", "hours": "Saat", "minutes": "Dakika", - "unlimited": "" + "unlimited": "Limitsiz olması için boş bırakın" } }, "clock": { - "name": "", + "name": "Tarih ve Saat", "description": "Geçerli tarih ve saati görüntüler.", "option": { "customTitleToggle": { - "label": "", - "description": "" + "label": "Özel Başlık/Şehir gösterimi", + "description": "Saatin üstüne özel bir başlık veya şehir/ülke adını ekleyin." }, "customTitle": { - "label": "" + "label": "Başlık" }, "is24HourFormat": { - "label": "", - "description": "" + "label": "24 saatlik format", + "description": "12 saatlik format yerine 24 saatlik formatı kullanın" }, "showSeconds": { - "label": "" + "label": "Saniyeleri görüntüle" }, "useCustomTimezone": { - "label": "" + "label": "Sabit bir zaman dilimi kullanın" }, "timezone": { "label": "Saat dilimi", - "description": "" + "description": "IANA standardına uygun zaman dilimini seçin" }, "showDate": { - "label": "" + "label": "Tarihi göster" }, "dateFormat": { - "label": "", - "description": "" + "label": "Tarih Biçimi", + "description": "Tarihin nasıl görüneceği" } } }, + "minecraftServerStatus": { + "name": "Minecraft Sunucu Durumu", + "description": "Minecraft sunucusunuzun durumunu görüntüler", + "option": { + "title": { + "label": "Başlık" + }, + "domain": { + "label": "Sunucu adresi" + }, + "isBedrockServer": { + "label": "Bedrock sunucusu" + } + }, + "status": { + "online": "Çevrimiçi", + "offline": "Çevrimdışı" + } + }, "notebook": { - "name": "Not defteri", - "description": "", + "name": "Not Defteri", + "description": "Markdown'ı destekleyen basit bir not defteri bileşeni", "option": { "showToolbar": { "label": "Markdown'da yazarken size yardımcı olacak araç çubuğunu aktif edin" @@ -1067,7 +1222,7 @@ "decreaseIndent": "Girintiyi Azalt", "link": "Bağlantı", "unlink": "Bağlantıyı kaldır", - "image": "Resim Göm", + "image": "Görsel Yerleştir", "addTable": "Tablo ekle", "deleteTable": "Tablo Sil", "colorCell": "Renk Hücresi", @@ -1095,7 +1250,7 @@ } }, "iframe": { - "name": "", + "name": "iFrame", "description": "İnternetten herhangi bir içeriği yerleştirin. Bazı web siteleri erişimi kısıtlayabilir.", "option": { "embedUrl": { @@ -1127,60 +1282,61 @@ } }, "error": { - "noUrl": "", + "noUrl": "IFrame URL'si sağlanmadı", + "unsupportedProtocol": "Sağlanan URL, desteklenmeyen bir protokol kullanıyor. Lütfen ({supportedProtocols})'den birini kullanın", "noBrowerSupport": "Tarayıcınız iframe'leri desteklemiyor. Lütfen tarayıcınızı güncelleyin." } }, "smartHome-entityState": { - "name": "", - "description": "", + "name": "Varlık Durumu", + "description": "Bir varlığın durumunu görüntüleyin ve isteğe bağlı olarak değiştirin", "option": { "entityId": { "label": "Varlık Kimliği" }, "displayName": { - "label": "" + "label": "Görünen isim" }, "entityUnit": { - "label": "" + "label": "Varlık Birimi" }, "clickable": { - "label": "" + "label": "Bir ögenin tıklanabilir olup olmadığı" } } }, "smartHome-executeAutomation": { - "name": "", - "description": "", + "name": "Otomasyon Yürüt", + "description": "Tek tıklamayla otomasyonu tetikleyin", "option": { "displayName": { - "label": "Ekran adı" + "label": "Görünen isim" }, "automationId": { "label": "Otomasyon Kimliği" } }, "spotlightAction": { - "run": "" + "run": "Çalıştır {name}" } }, "calendar": { "name": "Takvim", - "description": "", + "description": "Entegrasyonlarınızdaki etkinlikleri belirli bir göreli zaman dilimi içinde bir takvim görünümünde görüntüleyin", "option": { "releaseType": { "label": "Radarr yayın türü", "options": { - "inCinemas": "", - "digitalRelease": "", - "physicalRelease": "" + "inCinemas": "Sinemalarda", + "digitalRelease": "Dijital sürüm", + "physicalRelease": "Fiziksel Yayınlanan" } }, "filterPastMonths": { - "label": "" + "label": "Başlangıç" }, "filterFutureMonths": { - "label": "" + "label": "Bitiş" } } }, @@ -1189,24 +1345,24 @@ "description": "Belirlenen bir konumun güncel hava durumu bilgilerini görüntüler.", "option": { "isFormatFahrenheit": { - "label": "" + "label": "Fahrenheit cinsinden sıcaklık" }, "location": { "label": "Hava durumu konumu" }, "showCity": { - "label": "" + "label": "Şehri göster" }, "hasForecast": { - "label": "" + "label": "Hava tahmini göster" }, "forecastDayCount": { - "label": "", - "description": "" + "label": "Tahmin edilen gün sayısı", + "description": "Widget yeterince geniş olmadığında daha az gün gösterilir" }, "dateFormat": { - "label": "", - "description": "" + "label": "Tarih Biçimi", + "description": "Tarihin nasıl görüneceği" } }, "kind": { @@ -1227,17 +1383,17 @@ } }, "indexerManager": { - "name": "Dizin oluşturucu yöneticisi statüsü", - "description": "", + "name": "İndeksleyici Yönetim Durumu", + "description": "İndeksleyicilerinizin durumu", "option": { "openIndexerSiteInNewTab": { - "label": "" + "label": "İndeksleyici Sitesini Yeni Sekmede Aç" } }, - "title": "Dizin oluşturucu yöneticisi", + "title": "İndeksleyici Yöneticisi", "testAll": "Tümünü test et", "error": { - "internalServerError": "" + "internalServerError": "İndeksleyicilerin durumu alınamadı" } }, "healthMonitoring": { @@ -1258,41 +1414,41 @@ } }, "popover": { - "information": "", - "processor": "", - "memory": "", - "memoryAvailable": "", - "version": "", - "uptime": "", - "loadAverage": "", - "minute": "", - "minutes": "", - "used": "", - "available": "Mevcut", - "lastSeen": "" + "information": "Bilgi", + "processor": "İşlemci: {cpuModelName}", + "memory": "Bellek: {memory}GiB", + "memoryAvailable": "Kullanılabilir: {memoryAvailable} GiB ({percent}%)", + "version": "Sürüm: {version}", + "uptime": "Çalışma Süresi: {days} Gün, {hours} Saat, {minutes} Dakika", + "loadAverage": "Ortalama yük:", + "minute": "1 dakika", + "minutes": "{count} dakika", + "used": "Kullanılan", + "available": "Kullanılabilir", + "lastSeen": "Son durum güncellemesi: {lastSeen}" }, "memory": {}, "error": { - "internalServerError": "" + "internalServerError": "Sağlık durumu alınamadı" } }, "common": { "location": { - "query": "", - "latitude": "", - "longitude": "", - "disabledTooltip": "", - "unknownLocation": "", + "query": "Şehir / Posta kodu", + "latitude": "Enlem", + "longitude": "Boylam", + "disabledTooltip": "Lütfen bir şehir veya posta kodu girin", + "unknownLocation": "Bilinmeyen konum", "search": "Ara", "table": { "header": { - "city": "", - "country": "", - "coordinates": "", - "population": "" + "city": "Şehir", + "country": "Ülke", + "coordinates": "Koordinatlar", + "population": "Nüfus" }, "action": { - "select": "" + "select": "{city}, {countryCode}'i seçin" }, "population": { "fallback": "Bilinmeyen" @@ -1300,19 +1456,16 @@ } }, "integration": { - "noData": "", - "description": "" + "noData": "Hiçbir entegrasyon bulunamadı", + "description": "Yeni bir entegrasyon oluşturmak için tıklayın" }, "app": { - "noData": "", - "description": "" + "noData": "Uygulama bulunamadı", + "description": "Yeni bir uygulama oluşturmak için tıklayın" }, "error": { - "action": { - "logs": "" - }, - "noIntegration": "", - "noData": "" + "noIntegration": "Hiçbir entegrasyon seçilmedi", + "noData": "Entegrasyon verisi mevcut değil" }, "option": {} }, @@ -1325,128 +1478,133 @@ }, "hasAutoPlay": { "label": "Otomatik oynatma", - "description": "" + "description": "Otomatik oynatma yalnızca tarayıcı kısıtlamaları nedeniyle sessize alındığında çalışır" }, "isMuted": { - "label": "" + "label": "Sessiz" }, "hasControls": { - "label": "" + "label": "Kontrolleri göster" } }, "error": { - "noUrl": "", - "forYoutubeUseIframe": "" + "noUrl": "Video URL'si sağlanmadı", + "forYoutubeUseIframe": "YouTube videoları için iframe seçeneğini kullanın" } }, "mediaServer": { - "name": "", - "description": "", - "option": {} + "name": "Güncel Medya Sunucusu Akışları", + "description": "Medya sunucularınızdaki mevcut akışları gösterin", + "option": {}, + "items": { + "user": "Kullanıcı", + "name": "İsim", + "id": "Kimlik" + } }, "downloads": { - "name": "", - "description": "", + "name": "İndirme İstemcisi", + "description": "Hem Torrent hem de Usenet istemcilerinden indirdiklerinizi görüntülemenizi ve yönetmenizi sağlar.", "option": { "columns": { - "label": "" + "label": "Gösterilecek sütunlar" }, "enableRowSorting": { - "label": "" + "label": "Öğelerin sıralanmasını etkinleştir" }, "defaultSort": { - "label": "" + "label": "Öntanımlı olarak sıralama için kullanılan sütun" }, "descendingDefaultSort": { - "label": "" + "label": "Ters sıralama" }, "showCompletedUsenet": { - "label": "" + "label": "Tamamlanmış olarak işaretlenen usenet girdilerini göster" }, "showCompletedTorrent": { - "label": "" + "label": "Tamamlanmış olarak işaretlenen torrent girdilerini göster" }, "activeTorrentThreshold": { - "label": "" + "label": "Tamamlanan torrent'i bu eşik değerinin altına gizle (kiB/s cinsinden)" }, "categoryFilter": { - "label": "" + "label": "Filtrelenecek kategoriler/etiketler" }, "filterIsWhitelist": { - "label": "" + "label": "Beyaz liste olarak filtrele" }, "applyFilterToRatio": { - "label": "" + "label": "Oranı hesaplamak için filtreyi kullanın" } }, "errors": { - "noColumns": "", - "noCommunications": "" + "noColumns": "Öğelerdeki Sütunları Seç", + "noCommunications": "Entegrasyondan veri yüklenemiyor" }, "items": { "actions": { - "columnTitle": "" + "columnTitle": "Kontroller" }, "added": { - "columnTitle": "", + "columnTitle": "Ekleme", "detailsTitle": "Ekleme Tarihi" }, "category": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Ekstralar", + "detailsTitle": "Kategoriler (Veya ek bilgiler)" }, "downSpeed": { "columnTitle": "İndirme", "detailsTitle": "İndirme Hızı" }, "index": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "#", + "detailsTitle": "İstemci içindeki mevcut endeks" }, "id": { - "columnTitle": "" + "columnTitle": "İd" }, "integration": { "columnTitle": "Entegrasyon" }, "name": { - "columnTitle": "" + "columnTitle": "İş adı" }, "progress": { "columnTitle": "İlerleme", - "detailsTitle": "" + "detailsTitle": "İndirme İlerlemesi" }, "ratio": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Oran", + "detailsTitle": "Torrent oranı (alınan/gönderilen)" }, "received": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Toplam İndirme", + "detailsTitle": "Toplam indirilen" }, "sent": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Toplam gönderilen", + "detailsTitle": "Toplam Yüklenen" }, "size": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Dosya Boyutu", + "detailsTitle": "Seçilen dosyaların toplam boyutu" }, "state": { "columnTitle": "Durum", - "detailsTitle": "" + "detailsTitle": "İş Durumu" }, "time": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Bitiş zamanı", + "detailsTitle": "Tamamlanmasından bu yana geçen süre" }, "type": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "Tür", + "detailsTitle": "İndirme İstemcisi türü" }, "upSpeed": { "columnTitle": "Yükleme", - "detailsTitle": "" + "detailsTitle": "Gönderme Hızı" } }, "states": { @@ -1454,38 +1612,38 @@ "queued": "Sıraya alındı", "paused": "Duraklatıldı", "completed": "Tamamlanan", - "failed": "", - "processing": "", - "leeching": "", - "stalled": "", + "failed": "Başarısız", + "processing": "İşlemde", + "leeching": "Leechleme", + "stalled": "Durduruldu", "unknown": "Bilinmeyen", - "seeding": "" + "seeding": "Seed ediliyor" }, "actions": { "clients": { - "modalTitle": "", - "pause": "", - "resume": "" + "modalTitle": "İndirme istemcileri listesi", + "pause": "Tüm istemcileri/öğeleri duraklat", + "resume": "Tüm istemcileri/öğeleri sürdür" }, "client": { - "pause": "", - "resume": "" + "pause": "İstemciyi duraklat", + "resume": "İstemciyi sürdür" }, "item": { - "pause": "", - "resume": "", + "pause": "Öğeyi Duraklat", + "resume": "Öğeyi Sürdür", "delete": { - "title": "", - "modalTitle": "", - "entry": "", - "entryAndFiles": "" + "title": "Öğeyi Sil", + "modalTitle": "Bu işi silmek istediğinizden emin misiniz?", + "entry": "Girdiyi sil", + "entryAndFiles": "Girdiyi ve dosyaları sil" } } }, - "globalRatio": "" + "globalRatio": "Genel Oran" }, "mediaRequests-requestList": { - "name": "", + "name": "Medya İstekleri Listesi", "description": "Overseerr veya Jellyseerr uygulamanızdan gelen tüm medya taleplerinin bir listesini görün", "option": { "linksTargetNewTab": { @@ -1493,21 +1651,21 @@ } }, "pending": { - "approve": "", - "approving": "", - "decline": "" + "approve": "Talebi Onayla", + "approving": "Talep Onaylanıyor...", + "decline": "Talebi reddet" }, "availability": { "unknown": "Bilinmeyen", - "pending": "", - "processing": "", + "pending": "Bekleyen", + "processing": "İşlemde", "partiallyAvailable": "Kısmi", "available": "Mevcut" }, - "toBeDetermined": "" + "toBeDetermined": "-Yapım Aşamasında-" }, "mediaRequests-requestStats": { - "name": "", + "name": "Medya Talep İstatistikleri", "description": "Medya taleplerinizle ilgili istatistikler", "option": {}, "titles": { @@ -1515,98 +1673,172 @@ "main": "Medya İstatistikleri", "approved": "Onaylanan", "pending": "Onay bekleyen", - "processing": "", - "declined": "", - "available": "", + "processing": "İşleniyor", + "declined": "Reddedilen", + "available": "Mevcut", "tv": "Dizi talepleri", "movie": "Film talepleri", "total": "Toplam" }, "users": { "main": "En İyi Kullanıcılar", - "requests": "" + "requests": "Talepler" + } + } + }, + "mediaTranscoding": { + "name": "Medya Kod Dönüştürme", + "description": "Medya kod dönüştürmenizin istatistikleri, geçerli kuyruğu ve çalışan durumu", + "option": { + "defaultView": { + "label": "Varsayılan Görünüm" + }, + "queuePageSize": { + "label": "Kuyruk Sayfa Boyutu" + } + }, + "tab": { + "workers": "İşçiler", + "queue": "Kuyruk", + "statistics": "İstatistik" + }, + "currentIndex": "{start}-{end} / {total}", + "healthCheck": { + "title": "Sağlık kontrolü", + "queued": "Sıraya alındı", + "status": { + "healthy": "Sağlıklı", + "unhealthy": "Sağlıksız" + } + }, + "panel": { + "statistics": { + "empty": "Boş", + "transcodes": "Kod dönüştürmeler", + "transcodesCount": "Kod dönüştürmeler: {value}", + "healthChecksCount": "Sağlık kontrolleri: {value}", + "filesCount": "Dosyalar: {value}", + "savedSpace": "Kaydedilen alan: {value}", + "healthChecks": "Sağlık kontrolleri", + "videoCodecs": "Kodek'ler", + "videoContainers": "Konteyner", + "videoResolutions": "Çözünürlükler" + }, + "workers": { + "empty": "Boş", + "table": { + "file": "Dosya", + "eta": "ETA (Kalan Süre)", + "progress": "İlerleme", + "transcode": "Kod dönüştürme", + "healthCheck": "Sağlık kontrolü" + } + }, + "queue": { + "empty": "Boş", + "table": { + "file": "Dosya", + "size": "Boyut", + "transcode": "Kod dönüştürme", + "healthCheck": "Sağlık kontrolü" + } } } }, "rssFeed": { - "name": "", - "description": "", + "name": "RSS Beslemeleri", + "description": "Bir veya daha fazla RSS, ATOM veya JSON beslemesini takip edin ve görüntüleyin", "option": { "feedUrls": { - "label": "" + "label": "Besleme URL'leri" }, "enableRtl": { - "label": "" + "label": "RTL'yi etkinleştir" }, "textLinesClamp": { - "label": "" + "label": "Açıklamalarda satır sınırı" }, "maximumAmountPosts": { - "label": "" + "label": "Gönderi sayısı sınırı" } } } }, "widgetPreview": { "toggle": { - "enabled": "", - "disabled": "" + "enabled": "Düzenleme modu etkinleştirildi", + "disabled": "Düzenleme modu devre dışı bırakıldı" }, "dimensions": { - "title": "" + "title": "Boyutları değiştir" } }, "board": { "action": { + "duplicate": { + "title": "Paneli Kopyala", + "message": "{name} panelini tüm içerikleri ile birlikte kopyalamayı seçtiniz. Kullanım yetkiniz olmayan entegrasyonlar ve bunları içeren araçlar dahil edilmeyecektir.", + "notification": { + "success": { + "title": "Panel Kopyalandı", + "message": "Panel başarıyla kopyalandı" + }, + "error": { + "title": "Panel Kopyalanamıyor", + "message": "Panel kopyalanamadı" + } + } + }, "edit": { "notification": { "success": { - "title": "", - "message": "" + "title": "Değişiklikler başarıyla uygulandı", + "message": "Panel başarıyla kaydedildi" }, "error": { - "title": "", - "message": "" + "title": "Değişiklikler uygulanamıyor", + "message": "Panel kaydedilemedi" } }, "confirmLeave": { - "title": "", - "message": "" + "title": "Kaydedilmemiş değişiklikler", + "message": "Kaydedilmemiş değişiklikleriniz var, çıkmak istediğinizden emin misiniz?" } }, "oldImport": { - "label": "", + "label": "Homarr 1.0'dan önceki yedeğinizi içe aktarın", "notification": { "success": { - "title": "", - "message": "" + "title": "İçe aktarma başarılı", + "message": "Panel başarıyla içe aktarıldı" }, "error": { - "title": "", - "message": "" + "title": "İçe aktarma başarısız oldu", + "message": "Panel içe aktarılamadı, daha fazla ayrıntı için günlükleri kontrol edin" } }, "form": { "file": { - "label": "", - "invalidError": "" + "label": "JSON Dosyası Seç", + "invalidError": "Geçersiz yapılandırma dosyası" }, "apps": { "label": "Uygulamalar", "avoidDuplicates": { - "label": "", - "description": "" + "label": "Tekrarlardan kaçının", + "description": "Aynı href'e sahip bir uygulamanın zaten mevcut olduğu uygulamaları yok sayar" }, "onlyImportApps": { - "label": "", - "description": "" + "label": "Yalnızca uygulamaları içe aktar", + "description": "Sadece uygulamaları ekler, panelin manuel olarak yeniden oluşturulması gerekir" } }, "name": { - "label": "" + "label": "Panel adı" }, "screenSize": { - "label": "", + "label": "Ekran boyutu", + "description": "1.0'dan önceki sürümlerde üç farklı mod mevcuttu, yani her ekran boyutu için sütun miktarını seçebiliyordunuz.", "option": { "sm": "Küçük", "md": "Orta", @@ -1614,16 +1846,16 @@ } }, "sidebarBehavior": { - "label": "", - "description": "", + "label": "Kenar çubuğu davranışı", + "description": "Kenar çubukları 1.0'da kaldırıldı, içlerindeki öğelere ne olacağını seçebilirsiniz.", "option": { "lastSection": { - "label": "", - "description": "" + "label": "Son bölüm", + "description": "Kenar çubuğu son bölümün altında görüntülenecektir" }, "removeItems": { - "label": "", - "description": "" + "label": "Öğeleri kaldır", + "description": "Kenar çubuğunda bulunan öğeler kaldırılacak" } } } @@ -1632,64 +1864,64 @@ }, "field": { "pageTitle": { - "label": "" + "label": "Sayfa Başlığı" }, "metaTitle": { - "label": "" + "label": "Meta Başlığı" }, "logoImageUrl": { - "label": "" + "label": "Logo Görseli URL'si" }, "faviconImageUrl": { - "label": "" + "label": "Favicon Görseli URL'si" }, "backgroundImageUrl": { - "label": "" + "label": "Arkaplan Resmi URL'si" }, "backgroundImageAttachment": { - "label": "Arkaplan resim ekle", + "label": "Arka Plan Yerleşimi", "option": { "fixed": { - "label": "", - "description": "" + "label": "Sabit", + "description": "Arka plan aynı pozisyonda kalır." }, "scroll": { - "label": "", - "description": "" + "label": "Kaydır", + "description": "Arkaplan Farenizle Birlikte Kayar." } } }, "backgroundImageRepeat": { - "label": "", + "label": "Arkaplan Resmini Tekrarla", "option": { "repeat": { - "label": "", - "description": "" + "label": "Tekrarla", + "description": "Görsel, tüm arka plan alanını kaplayacak kadar tekrarlanır." }, "no-repeat": { - "label": "", - "description": "" + "label": "Tekrarlama Yok", + "description": "Görsel tekrarlanmaz ve tüm alanı doldurmayabilir." }, "repeat-x": { - "label": "", - "description": "" + "label": "Y tekrarla", + "description": "'Tekrarla' ile aynı, ancak yalnızca yatay eksende." }, "repeat-y": { - "label": "", - "description": "" + "label": "D tekrarla", + "description": "'Tekrarla' ile aynı ancak sadece dikey eksende." } } }, "backgroundImageSize": { - "label": "Arkaplan resim boyutu", + "label": "Arkaplan Resim Boyutu", "option": { "cover": { - "label": "", - "description": "" + "label": "Kapak", + "description": "Aşırı alanı kırparak resmi mümkün olduğunca küçülterek tüm pencereyi kaplar." }, "contain": { - "label": "", - "description": "" + "label": "Kapsama", + "description": "Resmi kırpmadan veya germeden, kapsayıcısı içinde mümkün olduğunca büyük olarak ayarlar." } } }, @@ -1700,36 +1932,36 @@ "label": "İkincil renk" }, "opacity": { - "label": "" + "label": "Opaklık" }, "customCss": { - "label": "", - "description": "Ayrıca, yalnızca deneyimli kullanıcılar için önerilen CSS kullanarak kontrol panelinizi özelleştirin", + "label": "Bu panel için özel css", + "description": "CSS kullanarak panelizi özelleştirin, sadece tecrübeli kullanıcılar için tavsiye edilir", "customClassesAlert": { - "title": "", - "description": "" + "title": "Özel sınıflar", + "description": "Düzenlenen her aracın gelişmiş seçenekler sekmesinde bulunan alanı kullanarak panel öğelerinizi CSS ile özelleştirebilir ve ya yukarıdaki özel CSS alanını kullanabilirsiniz." } }, "columnCount": { - "label": "" + "label": "Sütun Sayısı" }, "name": { "label": "İsim" }, "isPublic": { "label": "Herkese açık", - "description": "" + "description": "Herkese açık panellere, henüz hesap oluşturmamış kullanıcılar erişebilir." } }, "content": { - "metaTitle": "" + "metaTitle": "{boardName} panel" }, "setting": { - "title": "", + "title": "{boardName} paneli için ayarlar", "section": { "general": { "title": "Genel", - "unrecognizedLink": "" + "unrecognizedLink": "Sağlanan bağlantı tanınmıyor ve önizleme yapılmıyor, yine de çalışabilir." }, "layout": { "title": "Düzen" @@ -1738,107 +1970,140 @@ "title": "Arkaplan" }, "color": { - "title": "" + "title": "Renkler" }, "customCss": { - "title": "" + "title": "Özel Css" }, "access": { - "title": "", + "title": "Erişim Kontrolü", "permission": { "item": { "view": { "label": "Panelleri görüntüle" }, "modify": { - "label": "" + "label": "Paneli değiştir" }, "full": { - "label": "" + "label": "Tam erişim" } } } }, "dangerZone": { - "title": "Tehlikeli bölge", + "title": "Tehlikeli Bölge", "action": { "rename": { - "label": "", - "description": "", - "button": "", + "label": "Panelin ismini değiştir", + "description": "İsmin değiştirilmesi bu panele olan tüm bağlantıların kopmasına neden olacaktır.", + "button": "İsmi değiştir", "modal": { - "title": "" + "title": "Panelin ismini değiştir" } }, "visibility": { - "label": "", + "label": "Panelin görünürlüğünü değiştir", "description": { - "public": "", - "private": "" + "public": "Bu panel şu anda herkese açıktır.", + "private": "Bu panel şu anda özeldir." }, "button": { - "public": "", - "private": "" + "public": "Özel hale getir", + "private": "Herkese açık yap" }, "confirm": { "public": { - "title": "", - "description": "" + "title": "Paneli özel yap", + "description": "Bu paneli gizli yapmak istediğinizden emin misiniz? Bu, paneli herkese gizleyecektir. Misafir kullanıcılar için bağlantılar bozulacaktır." }, "private": { - "title": "", - "description": "" + "title": "Paneli herkese açık hale getir", + "description": "Bu paneli herkese açık yapmak istediğinizden emin misiniz? Bu, panelin herkes tarafından erişilebilir olmasını sağlayacaktır." } } }, "delete": { - "label": "", - "description": "", - "button": "", + "label": "Bu paneli sil", + "description": "Panel silmenin geri dönüşü yoktur. Lütfen emin olun.", + "button": "Bu paneli sil", "confirm": { "title": "Paneli sil", - "description": "" + "description": "Bu paneli silmek istediğinizden emin misiniz? Bu, paneli ve tüm içeriğini kalıcı olarak silecektir." } } } } } + }, + "error": { + "noBoard": { + "title": "Homarr'a Hoş Geldiniz", + "description": "Tüm uygulamalarınızı ve hizmetlerinizi parmaklarınızın ucuna getiren şık ve modern bir gösterge paneli.", + "link": "İlk panelinizi oluşturun", + "notice": "Bu sayfanın kaybolmasını sağlamak için bir panel oluşturun ve bunu ana panel olarak ayarlayın" + }, + "notFound": { + "title": "Panel bulunamadı", + "description": "Belirtilen panel bulunamadı veya panele erişiminiz yok.", + "link": "Tüm panelleri görüntüle", + "notice": "Bağlantıyı kontrol edin veya erişilebilir olması gerektiğini düşünüyorsanız bir yöneticiyle iletişime geçin" + }, + "homeBoard": { + "title": "Öntanımlı Panel Yapılandırılmadı", + "admin": { + "description": "Sunucu için henüz bir ana sayfa paneli belirlemediniz.", + "link": "Sunucu geneli için ana panel yapılandırın", + "notice": "Bu sayfayı tüm kullanıcılardan gizlemek için sunucu için bir ana panel ayarlayın" + }, + "user": { + "description": "Henüz bir ev paneli belirlemediniz.", + "link": "Öntanımlı paneli yapılandır", + "notice": "Bu sayfanın kaybolmasını sağlamak için tercihlerden öntanımlı panel seçin" + }, + "anonymous": { + "description": "Sunucu yöneticiniz henüz bir öntanımlı panel belirlemedi.", + "link": "Herkese açık panelleri görüntüle", + "notice": "Bu sayfanın kaybolmasını sağlamak için sunucu yöneticisinden öntanımlı panel ayarlamasını isteyin" + } + } } }, "management": { - "metaTitle": "", + "metaTitle": "Yönetim", "title": { - "morning": "", - "afternoon": "", - "evening": "" + "morning": "Günaydın, {username}", + "afternoon": "İyi günler, {username}", + "evening": "İyi akşamlar, {username}" }, "notFound": { - "title": "", - "text": "" + "title": "Bulunamadı", + "text": "İstenen kaynak bulunamadı" }, "navbar": { "items": { - "home": "Ana sayfa", + "home": "Ana Sayfa", "boards": "Paneller", "apps": "Uygulamalar", - "integrations": "", - "searchEngies": "", - "medias": "", + "integrations": "Entegrasyonlar", + "searchEngies": "Arama Motorları", + "medias": "Medyalar", "users": { "label": "Kullanıcılar", "items": { "manage": "Yönet", "invites": "Davetler", - "groups": "" + "groups": "Gruplar" } }, "tools": { "label": "Araçlar", "items": { - "docker": "", - "logs": "", - "api": "", - "tasks": "" + "docker": "Docker", + "logs": "Günlükler", + "api": "API", + "certificates": "", + "tasks": "Görevler" } }, "settings": "Ayarlar", @@ -1846,9 +2111,9 @@ "label": "Yardım", "items": { "documentation": "Dokümantasyon", - "submitIssue": "", + "submitIssue": "Bir Hata Gönder", "discord": "Discord Topluluğu", - "sourceCode": "" + "sourceCode": "Kaynak Kodu" } }, "about": "Hakkında" @@ -1860,47 +2125,57 @@ "board": "Paneller", "user": "Kullanıcılar", "invite": "Davetler", - "integration": "", + "integration": "Entegrasyonlar", "app": "Uygulamalar", - "group": "" + "group": "Gruplar" }, "statisticLabel": { "boards": "Paneller", - "resources": "", - "authentication": "", - "authorization": "" + "resources": "Kaynaklar", + "authentication": "Kimlik doğrulama", + "authorization": "Yetkilendirme" } }, "board": { "title": "Panelleriniz", "action": { "new": { - "label": "" + "label": "Yeni Panel" }, "open": { - "label": "" + "label": "Panel'i aç" }, "settings": { "label": "Ayarlar" }, "setHomeBoard": { - "label": "", + "label": "Öntanımlı Panel Olarak Ata", "badge": { - "label": "Ana sayfa", - "tooltip": "" + "label": "Ana Sayfa", + "tooltip": "Bu panel sizin öntanımlı paneliniz olarak görüntülenecektir" } }, + "setMobileHomeBoard": { + "label": "Mobil Panel Olarak Ata", + "badge": { + "label": "Mobil", + "tooltip": "Bu panel sizin mobil paneliniz olarak görüntülenecektir" + } + }, + "duplicate": { + "label": "Paneli Kopyala" + }, "delete": { "label": "Kalıcı olarak sil", "confirm": { "title": "Paneli sil", - "description": "" + "description": "{name} panelini silmek istediğinizden emin misiniz?" } } }, "visibility": { - "public": "", - "private": "" + "public": "Bu panel herkese açıktır", + "private": "Bu panel özeldir" }, "modal": { "createBoard": { @@ -1913,17 +2188,24 @@ } }, "media": { - "includeFromAllUsers": "" + "includeFromAllUsers": "Tüm kullanıcıların medyalarını dahil et" }, "user": { - "back": "", - "fieldsDisabledExternalProvider": "", + "back": "Kullanıcılara geri dön", + "fieldsDisabledExternalProvider": "Bazı alanlar harici bir kimlik doğrulama sağlayıcısı tarafından yönetildiği için devre dışıdır.", "setting": { "general": { "title": "Genel", "item": { - "language": "", - "board": "", + "language": "Dil & Bölge", + "board": { + "title": "Ana Panel", + "type": { + "general": "Genel", + "mobile": "Mobil" + } + }, + "defaultSearchEngine": "Öntanımlı arama motoru", "firstDayOfWeek": "Haftanın ilk günü", "accessibility": "Erişilebilirlik" } @@ -1940,50 +2222,50 @@ "title": "Kullanıcılar" }, "edit": { - "metaTitle": "" + "metaTitle": "Kullanıcıyı düzenle {username}" }, "create": { "metaTitle": "Kullanıcı ekle", - "title": "", + "title": "Yeni Kullanıcı Oluştur", "step": { "personalInformation": { - "label": "" + "label": "Kişisel bilgiler" }, "security": { "label": "Güvenlik" }, "groups": { - "label": "", - "title": "", - "description": "" + "label": "Gruplar", + "title": "Kullanıcının üye olması gereken tüm grupları seçin", + "description": "{everyoneGroup} grubu tüm kullanıcılara atanmıştır ve kaldırılamaz." }, "review": { - "label": "" + "label": "Gözden geçir" }, "completed": { - "title": "" + "title": "Kullanıcı oluşturuldu" }, "error": { - "title": "" + "title": "Kullanıcı oluşturma başarısız oldu" } }, "action": { - "createAnother": "", - "back": "" + "createAnother": "Başka bir kullanıcı oluştur", + "back": "Kullanıcı listesine geri dön" } }, "invite": { - "title": "Kullanıcı davetlerini yönet", + "title": "Kullanıcı Davetlerini Yönet", "action": { "new": { - "title": "", + "title": "Yeni Davet", "description": "Süre sona erdikten sonra davet artık geçerli olmayacak ve daveti alan kişi bir hesap oluşturamayacaktır." }, "copy": { - "title": "", - "description": "", + "title": "Davetiyeyi kopyala", + "description": "Davetiyeniz oluşturuldu. Bu modal kapandıktan sonra, bu bağlantıyı artık kopyalayamayacaksınız. Söz konusu kişiyi davet etmekten vazgeçerseniz, bu daveti istediğiniz zaman silebilirsiniz.", "link": "Davet bağlantısı", - "button": "" + "button": "Kopyala & kapat" }, "delete": { "title": "Daveti sil", @@ -2001,29 +2283,29 @@ "label": "Son geçerlilik tarihi" }, "token": { - "label": "Erişim Anahtarı" + "label": "Token" } } } }, "group": { - "back": "", + "back": "Gruplara geri dön", "setting": { "general": { "title": "Genel", - "owner": "", - "ownerOfGroup": "", - "ownerOfGroupDeleted": "" + "owner": "Sahip", + "ownerOfGroup": "Bu grubun sahibi", + "ownerOfGroupDeleted": "Bu grubun sahibi silindi. Şu anda bir sahibi yok." }, "members": { - "title": "", - "search": "", - "notFound": "" + "title": "Üyeler", + "search": "Bir üye bul", + "notFound": "Üye bulunamadı" }, "permissions": { - "title": "", + "title": "İzinler", "form": { - "unsavedChanges": "" + "unsavedChanges": "Kaydedilmemiş değişiklikleriniz var!" } } } @@ -2032,137 +2314,154 @@ "title": "Ayarlar", "notification": { "success": { - "message": "" + "message": "Ayarlar başarıyla kaydedildi" }, "error": { - "message": "" + "message": "Ayarlar kaydedilemedi" } }, "section": { "analytics": { - "title": "", + "title": "Analiz", "general": { - "title": "", - "text": "" + "title": "Anonim analizler gönder", + "text": "Homarr, açık kaynaklı yazılım Umami'yi kullanarak anonimleştirilmiş analizler gönderecektir. Hiçbir zaman kişisel bilgi toplamaz ve bu nedenle tamamen GDPR ve CCPA uyumludur. Analizleri etkinleştirmenizi öneririz çünkü, açık kaynak yazılım ekibimizin sorunları daha hızlı belirlemesine ve işlerimizi önceliklendirmesine yardımcı olmaktadır." }, "widgetData": { - "title": "", - "text": "" + "title": "Widget verileri", + "text": "Araç (ve sayılarını) yapılandırma verilerini gönder. URL'leri, alan adlarını veya başka herhangi bir veriyi içermez." }, "integrationData": { - "title": "", - "text": "" + "title": "Entegrasyon verileri", + "text": "Entegrasyon (ve sayıları) yapılandırma verilerini gönder. URL'leri, alan adlarını veya başka herhangi bir veriyi içermez." }, "usersData": { - "title": "", - "text": "" + "title": "Kullanıcı verileri", + "text": "Kullanıcı sayısını ve SSO etkinleştirme verilerini gönder" } }, "crawlingAndIndexing": { - "title": "", - "warning": "", + "title": "Arama ve İndeksleme", + "warning": "Buradaki ayarların etkinleştirilmesi veya devre dışı bırakılması, arama motorlarının sayfanızı arama ve indekleme şeklini ciddi şekilde etkileyecektir. Her ayar bir istek başlatır ve bu ayarları almak tarayıcının görevidir. Değişiklikler birkaç gün veya hafta sürebilir. Bazı ayarlar arama motoruna özel olabilir.", "noIndex": { - "title": "", - "text": "" + "title": "İndeksleme Yapma", + "text": "Web sitesini arama motorlarında indekslemeyin veya herhangi bir arama sonucunda görüntülemeyin" }, "noFollow": { - "title": "", - "text": "" + "title": "Bağlantıları Takip Etme", + "text": "İndeksleme sırasında bağlantıları takip etmeyin. Bunu devre dışı bırakmak, tarayıcıların Homarr'daki tüm bağlantıları izlemeye çalışmasına neden olur." }, "noTranslate": { - "title": "", - "text": "" + "title": "Çeviri Yapma", + "text": "Kullanıcının site üzerinde okumak isteyeceği dilin olmaması durumunda Google, arama sonuçlarında bir çeviri bağlantısı gösterecektir" }, "noSiteLinksSearchBox": { - "title": "", - "text": "" + "title": "Site Arama Alanını Gösterme", + "text": "Google, aranan bağlantıların yanı sıra diğer doğrudan bağlantılardan oluşan bir arama kutusu oluşturur. Bu seçenek etkinleştirildiğinde Google'dan bu alanı devre dışı bırakması istenecektir." } }, "board": { - "title": "", + "title": "Paneller", "homeBoard": { - "label": "", - "description": "" + "label": "Genel Ana Sayfa Paneli", + "mobileLabel": "Genel Mobil Panel", + "description": "Seçim yalnızca herkese açık paneller için kullanılabilir" + } + }, + "search": { + "title": "Ara", + "defaultSearchEngine": { + "label": "Genel öntanımlı arama motoru", + "description": "Entegrasyona bağlı arama motorları burada seçilemez" } }, "appearance": { - "title": "", + "title": "Görünüş", "defaultColorScheme": { - "label": "", + "label": "Öntanımlı Renk Düzeni", "options": { - "light": "", - "dark": "" + "light": "Aydınlık", + "dark": "Koyu" } } }, "culture": { - "title": "", + "title": "Kültür", "defaultLocale": { - "label": "" + "label": "Öntanımlı Dil" } } } }, "tool": { "tasks": { - "title": "", + "title": "Görevler", "status": { - "idle": "", + "idle": "Boşta", "running": "Çalışıyor", "error": "Hata" }, "job": { + "minecraftServerStatus": { + "label": "Minecraft sunucu durumu" + }, "iconsUpdater": { - "label": "" + "label": "Simge Güncelleme" }, "analytics": { - "label": "" + "label": "Analiz" }, "smartHomeEntityState": { - "label": "" + "label": "Akıllı Ev Varlık Durumu" }, "ping": { - "label": "" + "label": "Pingler" }, "mediaServer": { "label": "Medya Sunucusu" }, "mediaOrganizer": { - "label": "" + "label": "Medya Düzenleyicileri" }, "downloads": { - "label": "" + "label": "İndirmeler" }, "mediaRequestStats": { - "label": "" + "label": "Medya Talep İstatistikleri" }, "mediaRequestList": { - "label": "" + "label": "Medya Talep Listesi" }, "rssFeeds": { - "label": "" + "label": "RSS Beslemeleri" }, "indexerManager": { - "label": "" + "label": "İndeksleyici Yöneticisi" }, "healthMonitoring": { - "label": "" + "label": "Sağlık İzleme" }, "dnsHole": { - "label": "" + "label": "DNS Çözümleyici Verileri" }, "sessionCleanup": { - "label": "" + "label": "Oturum Temizleme" + }, + "updateChecker": { + "label": "Güncelleme denetleyicisi" + }, + "mediaTranscoding": { + "label": "Medya Kod Dönüştürme" } } }, "api": { - "title": "", + "title": "API", "modal": { "createApiToken": { - "title": "", - "description": "", - "button": "" + "title": "API token'ı oluşturuldu", + "description": "API anahtarı oluşturuldu. Dikkatli olun, bu anahtar veritabanında şifrelenmiştir ve size bir daha asla aktarılmayacaktır. Bu anaharı kaybederseniz, bir daha erişmeniz mümkün değildir.", + "button": "Kopyala ve kapat" } }, "tab": { @@ -2170,15 +2469,15 @@ "label": "Dokümantasyon" }, "apiKey": { - "label": "", - "title": "", + "label": "Kimlik doğrulama", + "title": "API Anahtarları", "button": { - "createApiToken": "" + "createApiToken": "API token'ı oluştur" }, "table": { "header": { "id": "Kimlik", - "createdBy": "" + "createdBy": "Tarafından oluşturuldu" } } } @@ -2186,31 +2485,31 @@ } }, "about": { - "version": "", - "text": "", + "version": "Sürüm {version}", + "text": "Homarr, gönüllüler tarafından sürdürülen topluluk odaklı bir açık kaynak projesidir. Bu kişiler sayesinde Homarr, 2021'den bugüne büyüyerek ilerleyen bir projedir. Ekibimiz, boş zamanlarında Homarr üzerinde birçok farklı ülkeden tamamen uzaktan, hiçbir ücret almadan çalışmaktadır.", "accordion": { "contributors": { - "title": "", - "subtitle": "" + "title": "Katkıda Bulunanlar", + "subtitle": "{count} kod & Homarr yazarı" }, "translators": { - "title": "", - "subtitle": "" + "title": "Çevirmenler", + "subtitle": "Birçok kişi Homarr'ın {count} dile çevrilmesine katkı sağlıyor" }, "libraries": { - "title": "", - "subtitle": "" + "title": "Kütüphaneler", + "subtitle": "Homarr kodlamasında {count} kütüphane kullanılıyor" } } } } }, "docker": { - "title": "Konteyner", + "title": "Konteynerler", "table": { - "updated": "", - "search": "", - "selected": "" + "updated": "{when} Güncellendi", + "search": "{count} konteyner içinde ara", + "selected": "{selectCount} / {totalCount} konteyner seçildi" }, "field": { "name": { @@ -2222,10 +2521,10 @@ "created": "Oluşturuldu", "running": "Çalışıyor", "paused": "Duraklatıldı", - "restarting": "Yeniden başlatılıyor", - "exited": "", + "restarting": "Yeniden Başlatılıyor", + "exited": "Durduruldu", "removing": "Kaldırılıyor", - "dead": "" + "dead": "Ölü" } }, "containerImage": { @@ -2240,12 +2539,12 @@ "label": "Başlat", "notification": { "success": { - "title": "", - "message": "" + "title": "Konteynerler başladı", + "message": "Konteynerler başarıyla başlatıldı" }, "error": { - "title": "", - "message": "" + "title": "Konteynerler başlatılmadı", + "message": "Konteynerler başlatılamadı" } } }, @@ -2253,12 +2552,12 @@ "label": "Durdur", "notification": { "success": { - "title": "", - "message": "" + "title": "Konteynerler durduruldu", + "message": "Konteynerler başarıyla durduruldu" }, "error": { - "title": "", - "message": "" + "title": "Konteynerler durdurulamadı", + "message": "Konteynerler durdurulamadı" } } }, @@ -2266,12 +2565,12 @@ "label": "Yeniden Başlat", "notification": { "success": { - "title": "", - "message": "" + "title": "Konteynerler yeniden başlatıldı", + "message": "Konteynerler başarıyla yeniden başlatıldı" }, "error": { - "title": "", - "message": "" + "title": "Konteynerler yeniden başlatılmadı", + "message": "Konteynerler yeniden başlatılamadı" } } }, @@ -2279,57 +2578,76 @@ "label": "Kaldır", "notification": { "success": { - "title": "", - "message": "" + "title": "Konteynerler kaldırıldı", + "message": "Konteynerler başarıyla kaldırıldı" }, "error": { - "title": "", - "message": "" + "title": "Konteynerler kaldırılmadı", + "message": "Konteynerler kaldırılamadı" } } }, "refresh": { - "label": "", + "label": "Yenile", "notification": { "success": { - "title": "", - "message": "" + "title": "Konteynerler yenilendi", + "message": "Şu anda en son verileri görüntülüyorsunuz" }, "error": { - "title": "", - "message": "" + "title": "Konteynerler yenilenmedi", + "message": "Konteynerler yenilenirken bir şeyler ters gitti" } } + }, + "addToHomarr": { + "label": "Homarr'a Ekle", + "notification": { + "success": { + "title": "Homarr'a Eklendi", + "message": "Seçili uygulamalar Homarr'a eklendi" + }, + "error": { + "title": "Homarr'a Eklenemedi", + "message": "Seçilen uygulamalar Homarr'a eklenemedi" + } + }, + "modal": { + "title": "Docker Konteynerleri Homarr'a Ekle" + } } + }, + "error": { + "internalServerError": "Docker konteynerlerları getirilemedi" } }, "permission": { - "title": "", + "title": "İzinler", "userSelect": { - "title": "" + "title": "Kullanıcı izni ekle" }, "groupSelect": { - "title": "" + "title": "Grup izni ekle" }, "tab": { "user": "Kullanıcılar", - "group": "", - "inherited": "" + "group": "Gruplar", + "inherited": "Devralınan gruplar" }, "field": { "user": { "label": "Kullanıcı" }, "group": { - "label": "" + "label": "Grup" }, "permission": { - "label": "" + "label": "İzin" } }, "action": { - "saveUser": "", - "saveGroup": "" + "saveUser": "Kullanıcı iznini kaydet", + "saveGroup": "Grup iznini kaydet" } }, "navigationStructure": { @@ -2339,30 +2657,30 @@ "label": "Paneller" }, "integrations": { - "label": "", + "label": "Entegrasyonlar", "edit": { "label": "Düzenle" }, "new": { - "label": "" + "label": "Yeni" } }, "search-engines": { - "label": "", + "label": "Arama Motorları", "new": { - "label": "" + "label": "Yeni" }, "edit": { "label": "Düzenle" } }, "medias": { - "label": "" + "label": "Medyalar" }, "apps": { "label": "Uygulamalar", "new": { - "label": "" + "label": "Yeni" }, "edit": { "label": "Düzenle" @@ -2377,7 +2695,7 @@ "security": "Güvenlik", "board": "Paneller", "groups": { - "label": "" + "label": "Gruplar" }, "invites": { "label": "Davetler" @@ -2386,9 +2704,12 @@ "tools": { "label": "Araçlar", "docker": { - "label": "" + "label": "Docker" }, "logs": { + "label": "Günlükler" + }, + "certificates": { "label": "" } }, @@ -2401,28 +2722,28 @@ } }, "search": { - "placeholder": "", - "nothingFound": "", + "placeholder": "Aramak için yaz", + "nothingFound": "Hiçbir şey bulunamadı", "error": { - "fetch": "" + "fetch": "Veriler alınırken bir hata oluştu" }, "mode": { "appIntegrationBoard": { - "help": "", + "help": "Uygulamalar, entegrasyonlar veya panellerde ara", "group": { "app": { "title": "Uygulamalar", "children": { "action": { "open": { - "label": "" + "label": "Uygulama Url'sini aç" }, "edit": { - "label": "" + "label": "Uygulamayı düzenle" } }, "detail": { - "title": "" + "title": "Uygulama için bir eylem seçin" } } }, @@ -2431,114 +2752,122 @@ "children": { "action": { "open": { - "label": "" + "label": "Panel'i aç" }, "homeBoard": { - "label": "" + "label": "Öntanımlı panel olarak ata" + }, + "mobileBoard": { + "label": "Mobil Panel Olarak Ata" }, "settings": { - "label": "" + "label": "Ayarları aç" } }, "detail": { - "title": "" + "title": "Panel için bir eylem seçin" } } }, "integration": { - "title": "" + "title": "Entegrasyonlar" } } }, "command": { - "help": "", + "help": "Komut modunu etkinleştir", "group": { "localCommand": { - "title": "" + "title": "Yerel komutlar" }, "globalCommand": { - "title": "", + "title": "Genel komutlar", "option": { "colorScheme": { - "light": "", - "dark": "" + "light": "Aydınlık Temaya Geç", + "dark": "Koyu Temaya Geç" }, "language": { - "label": "", + "label": "Dili değiştir", "children": { "detail": { - "title": "" + "title": "Tercih ettiğiniz dili seçin" } } }, "newBoard": { - "label": "" + "label": "Yeni Panel Oluştur" }, "importBoard": { - "label": "" + "label": "Bir paneli içe aktar" }, "newApp": { - "label": "" + "label": "Yeni Uygulama Oluştur" }, "newIntegration": { - "label": "", + "label": "Yeni Entegrasyon Oluştur", "children": { "detail": { - "title": "" + "title": "Oluşturmak istediğiniz entegrasyon türünü seçin" } } }, "newUser": { - "label": "" + "label": "Yeni Kullanıcı Oluştur" }, "newInvite": { - "label": "" + "label": "Yeni Davet Oluştur" }, "newGroup": { - "label": "" + "label": "Yeni Grup Oluştur" } } } } }, + "media": { + "requestMovie": "Filmi Talep Et", + "requestSeries": "Diziyi Talep Et", + "openIn": "{kind} üzerinde göster" + }, "external": { - "help": "", + "help": "Harici bir arama motoru kullanın", "group": { "searchEngine": { - "title": "", + "title": "Arama Motorları", "children": { "action": { "search": { - "label": "" + "label": "{name} ile ara" } }, "detail": { - "title": "" + "title": "Arama yapmak istediğiniz terimleri girin" }, "searchResults": { - "title": "" + "title": "Etkileşime geçmek için bir sonuç seçin" } }, "option": { "google": { - "name": "", - "description": "" + "name": "Google", + "description": "Google ile web'de arama yapın" }, "bing": { - "name": "", - "description": "" + "name": "Bing", + "description": "Bing ile web'de arama yapın" }, "duckduckgo": { - "name": "", - "description": "" + "name": "DuckDuckGo", + "description": "DuckDuckGo ile web'de arama yapın" }, "torrent": { "name": "Torrentler", - "description": "" + "description": "Torrentdownloads.pro'da torrentleri arayın" }, "youTube": { - "name": "", - "description": "" + "name": "YouTube", + "description": "YouTube'da video arayın" } } } @@ -2547,7 +2876,7 @@ "help": { "group": { "mode": { - "title": "" + "title": "Modlar" }, "help": { "title": "Yardım", @@ -2556,7 +2885,7 @@ "label": "Dokümantasyon" }, "submitIssue": { - "label": "" + "label": "Bir Hata Gönder" }, "discord": { "label": "Discord Topluluğu" @@ -2567,64 +2896,82 @@ }, "home": { "group": { + "search": { + "title": "Ara", + "option": { + "other": { + "label": "Farklı bir arama motoruyla arama yap" + }, + "no-default": { + "label": "Öntanımlı arama motoru yapılandırılmadı", + "description": "Tercihlerde öntanımlı arama motoru belirleyin" + }, + "search": { + "label": "{name} kullanarak \"{query}\" terimini ara" + }, + "from-integration": { + "description": "Aramak için yazmaya başla" + } + } + }, "local": { - "title": "" + "title": "Yerel sonuçlar" } } }, "page": { - "help": "", + "help": "Sayfalarda ara", "group": { "page": { - "title": "", + "title": "Sayfalar", "option": { "manageHome": { - "label": "" + "label": "Ana Sayfayı Yönet" }, "manageBoard": { - "label": "" + "label": "Panelleri yönet" }, "manageApp": { - "label": "" + "label": "Uygulamaları yönet" }, "manageIntegration": { - "label": "" + "label": "Entegrasyonları yönet" }, "manageSearchEngine": { - "label": "" + "label": "Arama motorlarını yönet" }, "manageMedia": { - "label": "" + "label": "Medyayı yönet" }, "manageUser": { "label": "Kullanıcıları yönet" }, "manageInvite": { - "label": "" + "label": "Davetiyeleri yönet" }, "manageGroup": { - "label": "" + "label": "Grupları yönet" }, "manageDocker": { - "label": "" + "label": "Docker'ı yönet" }, "manageApi": { - "label": "" + "label": "Swagger API'si" }, "manageLog": { - "label": "" + "label": "Günlükleri görüntüle" }, "manageTask": { - "label": "" + "label": "Görevleri yönet" }, "manageSettings": { - "label": "" + "label": "Genel ayarlar" }, "about": { "label": "Hakkında" }, "homeBoard": { - "label": "" + "label": "Öntanımlı panel" }, "preferences": { "label": "Tercihleriniz" @@ -2634,37 +2981,37 @@ } }, "userGroup": { - "help": "", + "help": "Kullanıcı veya gruplarda ara", "group": { "user": { "title": "Kullanıcılar", "children": { "action": { "detail": { - "label": "" + "label": "Kullanıcı ayrıntılarını göster" } }, "detail": { - "title": "" + "title": "Kullanıcı için bir eylem seçin" } } }, "group": { - "title": "", + "title": "Gruplar", "children": { "action": { "detail": { - "label": "" + "label": "Grup ayrıntılarını göster" }, "manageMember": { - "label": "" + "label": "Üyeleri yönet" }, "managePermission": { - "label": "" + "label": "İzinleri yönet" } }, "detail": { - "title": "" + "title": "Grup için bir eylem seçin" } } } @@ -2672,75 +3019,132 @@ } }, "engine": { - "search": "", + "search": "Bir arama motoru bulun", "field": { "name": { "label": "İsim" }, "short": { - "label": "" + "label": "Kısa Yol" }, "urlTemplate": { - "label": "" + "label": "URL arama şablonu" }, "description": { - "label": "" + "label": "Tanım" } }, "page": { "list": { - "title": "", + "title": "Arama Motorları", "noResults": { - "title": "", - "action": "" + "title": "Henüz bir arama motoru yapılandırılmadı", + "action": "İlk arama motorunuzu oluşturun" }, - "interactive": "" + "interactive": "Etkileşimli, entegrasyon kullanır" }, "create": { - "title": "", + "title": "Yeni Arama Motoru", "notification": { "success": { - "title": "", - "message": "" + "title": "Arama motoru oluşturuldu", + "message": "Arama motoru başarıyla oluşturuldu" }, "error": { - "title": "", - "message": "" + "title": "Arama motoru oluşturulmadı", + "message": "Arama motoru oluşturulamadı" } } }, "edit": { - "title": "", + "title": "Arama motorunu düzenle", "notification": { "success": { - "title": "", - "message": "" + "title": "Değişiklikler başarıyla uygulandı", + "message": "Arama motoru başarıyla kaydedildi" }, "error": { - "title": "", - "message": "" + "title": "Değişiklikler uygulanamıyor", + "message": "Arama motoru kaydedilemedi" } }, - "configControl": "", + "configControl": "Yapılandırma", "searchEngineType": { - "generic": "", - "fromIntegration": "" + "generic": "Kapsamlı", + "fromIntegration": "Entegrasyondan" } }, "delete": { - "title": "", - "message": "", + "title": "Arama motorunu sil", + "message": "'{name}' arama motorunu silmek istediğinizden emin misiniz?", "notification": { "success": { - "title": "", - "message": "" + "title": "Arama motoru silindi", + "message": "Arama motoru başarıyla silindi" }, "error": { - "title": "", - "message": "" + "title": "Arama motoru silinmedi", + "message": "Arama motoru silinemedi" } } } + }, + "media": { + "request": { + "modal": { + "title": "Talep Et \"{name}\"", + "table": { + "header": { + "season": "Sezon", + "episodes": "Bölüm" + } + }, + "button": { + "send": "Talep Gönder" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/tw.json b/packages/translation/src/lang/tw.json index 3335d6f5c..ce5e146a4 100644 --- a/packages/translation/src/lang/tw.json +++ b/packages/translation/src/lang/tw.json @@ -1,128 +1,864 @@ { + "init": { + "step": { + "start": { + "title": "歡迎來到 Homarr", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "應用", + "boards": "面板", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "Token", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "設定", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "使用者", "name": "使用者", + "page": { + "login": { + "title": "", + "subtitle": "" + }, + "invite": { + "title": "", + "subtitle": "", + "description": "" + }, + "init": { + "title": "", + "subtitle": "" + } + }, "field": { "email": { - "label": "E-mail" + "label": "E-mail", + "verified": "" }, "username": { - "label": "帳號" + "label": "使用者" }, "password": { "label": "密碼", "requirement": { + "length": "", "lowercase": "包含小寫字母", "uppercase": "包含大寫字母", - "number": "包含數字" + "number": "包含數字", + "special": "" } }, "passwordConfirm": { "label": "確認密碼" + }, + "previousPassword": { + "label": "" + }, + "homeBoard": { + "label": "" + }, + "pingIconsEnabled": { + "label": "" } }, + "error": { + "usernameTaken": "" + }, "action": { "login": { - "label": "登入" + "label": "登入", + "labelWith": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "forgotPassword": { + "label": "", + "description": "" + } }, "register": { "label": "創建帳號", "notification": { "success": { - "title": "帳號已創建" + "title": "帳號已創建", + "message": "" + }, + "error": { + "title": "", + "message": "" } } }, - "create": "創建使用者" + "create": "創建使用者", + "changePassword": { + "label": "", + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, + "changeHomeBoard": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, + "changeFirstDayOfWeek": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, + "changePingIconsEnabled": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, + "manageAvatar": { + "changeImage": { + "label": "", + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + }, + "toLarge": { + "title": "", + "message": "" + } + } + }, + "removeImage": { + "label": "", + "confirm": "", + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + } + }, + "editProfile": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, + "delete": { + "label": "", + "description": "", + "confirm": "" + }, + "select": { + "label": "", + "notFound": "" + }, + "transfer": { + "label": "" + } } }, "group": { + "title": "", + "name": "", + "search": "", "field": { - "name": "名稱" + "name": "名稱", + "members": "" }, "permission": { "admin": { - "title": "管理員" + "title": "管理員", + "item": { + "admin": { + "label": "", + "description": "" + } + } + }, + "app": { + "title": "應用", + "item": { + "create": { + "label": "", + "description": "" + }, + "use-all": { + "label": "", + "description": "" + }, + "modify-all": { + "label": "", + "description": "" + }, + "full-all": { + "label": "", + "description": "" + } + } }, "board": { - "title": "面板" + "title": "面板", + "item": { + "create": { + "label": "", + "description": "" + }, + "view-all": { + "label": "", + "description": "" + }, + "modify-all": { + "label": "", + "description": "" + }, + "full-all": { + "label": "", + "description": "" + } + } + }, + "integration": { + "title": "", + "item": { + "create": { + "label": "", + "description": "" + }, + "use-all": { + "label": "", + "description": "" + }, + "interact-all": { + "label": "", + "description": "" + }, + "full-all": { + "label": "", + "description": "" + } + } + }, + "media": { + "title": "", + "item": { + "upload": { + "label": "", + "description": "" + }, + "view-all": { + "label": "", + "description": "" + }, + "full-all": { + "label": "", + "description": "" + } + } + }, + "other": { + "title": "", + "item": { + "view-logs": { + "label": "", + "description": "" + } + } + }, + "search-engine": { + "title": "", + "item": { + "create": { + "label": "", + "description": "" + }, + "modify-all": { + "label": "", + "description": "" + }, + "full-all": { + "label": "", + "description": "" + } + } + } + }, + "memberNotice": { + "mixed": "", + "external": "" + }, + "reservedNotice": { + "message": "" + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, + "transfer": { + "label": "", + "description": "", + "confirm": "", + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, + "addMember": { + "label": "" + }, + "removeMember": { + "label": "", + "confirm": "" + }, + "delete": { + "label": "", + "description": "", + "confirm": "", + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, + "changePermissions": { + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "update": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, + "select": { + "label": "", + "notFound": "" } } }, "app": { "page": { "list": { - "title": "應用" + "title": "應用", + "noResults": { + "title": "", + "action": "" + } + }, + "create": { + "title": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "edit": { + "title": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "delete": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } }, "field": { "name": { "label": "名稱" + }, + "description": { + "label": "" + }, + "url": { + "label": "" + } + }, + "action": { + "select": { + "label": "", + "notFound": "" } } }, "integration": { + "page": { + "list": { + "title": "", + "search": "", + "noResults": { + "title": "" + } + }, + "create": { + "title": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "edit": { + "title": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "delete": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + } + }, "field": { "name": { "label": "名稱" + }, + "url": { + "label": "" } }, + "action": { + "create": "" + }, "testConnection": { + "action": { + "create": "", + "edit": "" + }, + "alertNotice": "", "notification": { + "success": { + "title": "", + "message": "" + }, "invalidUrl": { - "title": "無效連結" + "title": "無效連結", + "message": "" + }, + "secretNotDefined": { + "title": "", + "message": "" + }, + "invalidCredentials": { + "title": "", + "message": "" + }, + "commonError": { + "title": "", + "message": "" + }, + "badRequest": { + "title": "", + "message": "" + }, + "unauthorized": { + "title": "", + "message": "" + }, + "forbidden": { + "title": "", + "message": "" + }, + "notFound": { + "title": "", + "message": "" + }, + "internalServerError": { + "title": "", + "message": "" + }, + "serviceUnavailable": { + "title": "", + "message": "" + }, + "connectionAborted": { + "title": "", + "message": "" + }, + "domainNotFound": { + "title": "", + "message": "" + }, + "connectionRefused": { + "title": "", + "message": "" + }, + "invalidJson": { + "title": "", + "message": "" + }, + "wrongPath": { + "title": "", + "message": "" } } }, "secrets": { + "title": "", + "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, + "secureNotice": "", + "reset": { + "title": "", + "message": "" + }, + "noSecretsRequired": { + "segmentTitle": "", + "text": "" + }, "kind": { "username": { - "label": "帳號" + "label": "使用者", + "newLabel": "" + }, + "apiKey": { + "label": "", + "newLabel": "" }, "password": { "label": "密碼", "newLabel": "新密碼" } } + }, + "permission": { + "use": "", + "interact": "", + "full": "" } }, "media": { + "plural": "", + "search": "", "field": { "name": "名稱", "size": "大小", "creator": "創建者" + }, + "action": { + "upload": { + "label": "", + "file": "", + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, + "delete": { + "label": "", + "description": "", + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, + "copy": { + "label": "" + } } }, "common": { + "beta": "", "error": "錯誤", "action": { "add": "新增", "apply": "應用", + "backToOverview": "", "create": "創建", "edit": "編輯", + "import": "", "insert": "插入", "remove": "刪除", "save": "儲存", "saveChanges": "儲存設定", "cancel": "取消", "delete": "刪除", + "discard": "", "confirm": "確認", + "continue": "", "previous": "上一步", "next": "下一步", - "tryAgain": "請再試一次" + "checkoutDocs": "", + "checkLogs": "", + "tryAgain": "請再試一次", + "loading": "" + }, + "here": "", + "iconPicker": { + "label": "", + "header": "" + }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } }, "information": { + "min": "", + "max": "", + "days": "", "hours": "時", "minutes": "分" }, + "notification": { + "create": { + "success": "", + "error": "" + }, + "delete": { + "success": "", + "error": "" + }, + "update": { + "success": "", + "error": "" + }, + "transfer": { + "success": "", + "error": "" + } + }, + "multiSelect": { + "placeholder": "" + }, + "multiText": { + "placeholder": "", + "addLabel": "" + }, + "select": { + "placeholder": "", + "badge": { + "recommended": "" + } + }, "userAvatar": { "menu": { + "switchToDarkMode": "", + "switchToLightMode": "", + "management": "", "preferences": "您的偏好設定", - "login": "登入" + "logout": "", + "login": "登入", + "homeBoard": "", + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "危險", "noResults": "未找到結果", + "preview": { + "show": "", + "hide": "" + }, "zod": { "errors": { "default": "該字段無效", @@ -130,7 +866,8 @@ "string": { "startsWith": "該字段必須以 {startsWith} 開頭", "endsWith": "該字段必須以 {endsWith} 結尾", - "includes": "該字段必須以 {includes}" + "includes": "該字段必須以 {includes}", + "invalidEmail": "" }, "tooSmall": { "string": "該字段長度必須至少為 {minimum} 個字符", @@ -139,11 +876,30 @@ "tooBig": { "string": "該字段長度不得超過 {maximum} 個字符", "number": "該字段必須小於或等於 {maximum}" + }, + "custom": { + "passwordsDoNotMatch": "", + "passwordRequirements": "", + "boardAlreadyExists": "", + "invalidFileType": "", + "fileTooLarge": "", + "invalidConfiguration": "", + "groupNameTaken": "" } } } }, "section": { + "dynamic": { + "action": { + "create": "", + "remove": "" + }, + "remove": { + "title": "", + "message": "" + } + }, "category": { "field": { "name": { @@ -151,42 +907,147 @@ } }, "action": { + "create": "", + "edit": "", + "remove": "", "moveUp": "上移", - "moveDown": "下移" + "moveDown": "下移", + "createAbove": "", + "createBelow": "" + }, + "create": { + "title": "", + "submit": "" + }, + "remove": { + "title": "", + "message": "" + }, + "edit": { + "title": "", + "submit": "" }, "menu": { "label": { + "create": "", "changePosition": "換位" } } } }, "item": { + "action": { + "create": "", + "import": "", + "edit": "", + "moveResize": "", + "duplicate": "", + "remove": "" + }, "menu": { "label": { "settings": "設定" } }, + "create": { + "title": "", + "addToBoard": "" + }, "moveResize": { + "title": "", "field": { "width": { "label": "寬度" }, "height": { "label": "高度" + }, + "xOffset": { + "label": "" + }, + "yOffset": { + "label": "" } } + }, + "edit": { + "title": "", + "advancedOptions": { + "label": "", + "title": "" + }, + "field": { + "integrations": { + "label": "" + }, + "customCssClasses": { + "label": "" + } + } + }, + "remove": { + "title": "", + "message": "" } }, "widget": { "app": { + "name": "", + "description": "", "option": { + "appId": { + "label": "" + }, "openInNewTab": { "label": "在新分頁中開啟" + }, + "showTitle": { + "label": "" + }, + "showDescriptionTooltip": { + "label": "" + }, + "pingEnabled": { + "label": "" + } + }, + "error": { + "notFound": { + "label": "", + "tooltip": "" + } + } + }, + "bookmarks": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "layout": { + "label": "顯示布局", + "option": { + "row": { + "label": "橫向" + }, + "column": { + "label": "垂直" + }, + "grid": { + "label": "" + } + } + }, + "items": { + "label": "", + "add": "" } } }, "dnsHoleSummary": { + "name": "", + "description": "", "option": { "layout": { "label": "顯示布局", @@ -196,17 +1057,29 @@ }, "column": { "label": "垂直" + }, + "grid": { + "label": "" } } + }, + "usePiHoleColors": { + "label": "" } }, + "error": { + "internalServerError": "", + "integrationsDisconnected": "" + }, "data": { "adsBlockedToday": "今日封鎖", "adsBlockedTodayPercentage": "今日封鎖", - "dnsQueriesToday": "今日查詢" + "dnsQueriesToday": "今日查詢", + "domainsBeingBlocked": "" } }, "dnsHoleControls": { + "name": "", "description": "從您的面板控制 PiHole 或 AdGuard", "option": { "layout": { @@ -217,28 +1090,70 @@ }, "column": { "label": "垂直" + }, + "grid": { + "label": "" } } + }, + "showToggleAllButtons": { + "label": "" } }, + "error": { + "internalServerError": "" + }, "controls": { + "enableAll": "", + "disableAll": "", + "setTimer": "", "set": "設定", "enabled": "已啟用", "disabled": "已禁用", + "processing": "", + "disconnected": "", "hours": "時", - "minutes": "分" + "minutes": "分", + "unlimited": "" } }, "clock": { + "name": "", "description": "顯示目前的日期與時間", "option": { + "customTitleToggle": { + "label": "", + "description": "" + }, + "customTitle": { + "label": "" + }, + "is24HourFormat": { + "label": "", + "description": "" + }, + "showSeconds": { + "label": "" + }, + "useCustomTimezone": { + "label": "" + }, "timezone": { - "label": "時區" + "label": "時區", + "description": "" + }, + "showDate": { + "label": "" + }, + "dateFormat": { + "label": "", + "description": "" } } }, "notebook": { "name": "筆記本", + "description": "", "option": { "showToolbar": { "label": "顯示幫助您紀錄 Markdown 的工具欄" @@ -330,17 +1245,31 @@ } }, "error": { + "noUrl": "", "noBrowerSupport": "您的瀏覽器不支援iFrame,請更新您的瀏覽器" } }, "smartHome-entityState": { + "name": "", + "description": "", "option": { "entityId": { "label": "實體 ID" + }, + "displayName": { + "label": "" + }, + "entityUnit": { + "label": "" + }, + "clickable": { + "label": "" } } }, "smartHome-executeAutomation": { + "name": "", + "description": "", "option": { "displayName": { "label": "顯示名稱" @@ -348,13 +1277,28 @@ "automationId": { "label": "自動化ID" } + }, + "spotlightAction": { + "run": "" } }, "calendar": { "name": "日曆", + "description": "", "option": { "releaseType": { - "label": "Radarr 發布類型" + "label": "Radarr 發布類型", + "options": { + "inCinemas": "", + "digitalRelease": "", + "physicalRelease": "" + } + }, + "filterPastMonths": { + "label": "" + }, + "filterFutureMonths": { + "label": "" } } }, @@ -362,8 +1306,25 @@ "name": "天氣", "description": "顯示指定位置的目前天氣狀況", "option": { + "isFormatFahrenheit": { + "label": "" + }, "location": { "label": "天氣位置" + }, + "showCity": { + "label": "" + }, + "hasForecast": { + "label": "" + }, + "forecastDayCount": { + "label": "", + "description": "" + }, + "dateFormat": { + "label": "", + "description": "" } }, "kind": { @@ -385,8 +1346,17 @@ }, "indexerManager": { "name": "索引管理器狀態", + "description": "", + "option": { + "openIndexerSiteInNewTab": { + "label": "" + } + }, "title": "索引管理器", - "testAll": "測試全部" + "testAll": "測試全部", + "error": { + "internalServerError": "" + } }, "healthMonitoring": { "name": "系統健康監控", @@ -406,20 +1376,60 @@ } }, "popover": { - "available": "可用" + "information": "", + "processor": "", + "memory": "", + "memoryAvailable": "", + "version": "", + "uptime": "", + "loadAverage": "", + "minute": "", + "minutes": "", + "used": "", + "available": "可用", + "lastSeen": "" + }, + "memory": {}, + "error": { + "internalServerError": "" } }, "common": { "location": { + "query": "", + "latitude": "", + "longitude": "", + "disabledTooltip": "", + "unknownLocation": "", "search": "搜尋", "table": { - "header": {}, - "action": {}, + "header": { + "city": "", + "country": "", + "coordinates": "", + "population": "" + }, + "action": { + "select": "" + }, "population": { "fallback": "未知" } } - } + }, + "integration": { + "noData": "", + "description": "" + }, + "app": { + "noData": "", + "description": "" + }, + "error": { + "noIntegration": "", + "noData": "" + }, + "option": {} }, "video": { "name": "影片串流", @@ -429,33 +1439,134 @@ "label": "訂閱網址" }, "hasAutoPlay": { - "label": "自動播放" + "label": "自動播放", + "description": "" + }, + "isMuted": { + "label": "" + }, + "hasControls": { + "label": "" } + }, + "error": { + "noUrl": "", + "forYoutubeUseIframe": "" + } + }, + "mediaServer": { + "name": "", + "description": "", + "option": {}, + "items": { + "user": "使用者", + "name": "名稱", + "id": "" } }, "downloads": { + "name": "", + "description": "", + "option": { + "columns": { + "label": "" + }, + "enableRowSorting": { + "label": "" + }, + "defaultSort": { + "label": "" + }, + "descendingDefaultSort": { + "label": "" + }, + "showCompletedUsenet": { + "label": "" + }, + "showCompletedTorrent": { + "label": "" + }, + "activeTorrentThreshold": { + "label": "" + }, + "categoryFilter": { + "label": "" + }, + "filterIsWhitelist": { + "label": "" + }, + "applyFilterToRatio": { + "label": "" + } + }, + "errors": { + "noColumns": "", + "noCommunications": "" + }, "items": { + "actions": { + "columnTitle": "" + }, "added": { + "columnTitle": "", "detailsTitle": "日期已添加" }, + "category": { + "columnTitle": "", + "detailsTitle": "" + }, "downSpeed": { "columnTitle": "下載", "detailsTitle": "下載速度" }, + "index": { + "columnTitle": "", + "detailsTitle": "" + }, + "id": { + "columnTitle": "" + }, "integration": { "columnTitle": "集成" }, + "name": { + "columnTitle": "" + }, "progress": { - "columnTitle": "進度" + "columnTitle": "進度", + "detailsTitle": "" }, "ratio": { - "columnTitle": "分享率" + "columnTitle": "分享率", + "detailsTitle": "" + }, + "received": { + "columnTitle": "", + "detailsTitle": "" + }, + "sent": { + "columnTitle": "", + "detailsTitle": "" + }, + "size": { + "columnTitle": "", + "detailsTitle": "" }, "state": { - "columnTitle": "狀態" + "columnTitle": "狀態", + "detailsTitle": "" + }, + "time": { + "columnTitle": "", + "detailsTitle": "" + }, + "type": { + "columnTitle": "", + "detailsTitle": "" }, "upSpeed": { - "columnTitle": "上傳" + "columnTitle": "上傳", + "detailsTitle": "" } }, "states": { @@ -463,62 +1574,304 @@ "queued": "隊列", "paused": "已暫停", "completed": "已完成", - "unknown": "未知" - } + "failed": "", + "processing": "", + "leeching": "", + "stalled": "", + "unknown": "未知", + "seeding": "" + }, + "actions": { + "clients": { + "modalTitle": "", + "pause": "", + "resume": "" + }, + "client": { + "pause": "", + "resume": "" + }, + "item": { + "pause": "", + "resume": "", + "delete": { + "title": "", + "modalTitle": "", + "entry": "", + "entryAndFiles": "" + } + } + }, + "globalRatio": "" }, "mediaRequests-requestList": { + "name": "", "description": "查看 Overseerr 或 Jellyseer 實例中的所有媒體請求列表", "option": { "linksTargetNewTab": { "label": "在新分頁中開啟連結" } }, + "pending": { + "approve": "", + "approving": "", + "decline": "" + }, "availability": { "unknown": "未知", + "pending": "", + "processing": "", "partiallyAvailable": "部分", "available": "可用" - } + }, + "toBeDetermined": "" }, "mediaRequests-requestStats": { + "name": "", "description": "您的媒體請求統計", + "option": {}, "titles": { "stats": { "main": "媒體狀態", "approved": "已准許", "pending": "待准許", + "processing": "", + "declined": "", + "available": "", "tv": "電視劇請求", "movie": "電影請求", "total": "總計" }, "users": { - "main": "使用者排行" + "main": "使用者排行", + "requests": "" + } + } + }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "預設視圖" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "工作種", + "queue": "隊列", + "statistics": "統計" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "隊列", + "status": { + "healthy": "健康", + "unhealthy": "不良" + } + }, + "panel": { + "statistics": { + "empty": "空", + "transcodes": "轉碼", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "編碼", + "videoContainers": "容器", + "videoResolutions": "解析度" + }, + "workers": { + "empty": "空", + "table": { + "file": "檔案", + "eta": "剩餘時間", + "progress": "進度", + "transcode": "轉碼", + "healthCheck": "" + } + }, + "queue": { + "empty": "空", + "table": { + "file": "檔案", + "size": "大小", + "transcode": "轉碼", + "healthCheck": "" + } + } + } + }, + "rssFeed": { + "name": "", + "description": "", + "option": { + "feedUrls": { + "label": "" + }, + "enableRtl": { + "label": "" + }, + "textLinesClamp": { + "label": "" + }, + "maximumAmountPosts": { + "label": "" } } } }, + "widgetPreview": { + "toggle": { + "enabled": "", + "disabled": "" + }, + "dimensions": { + "title": "" + } + }, "board": { "action": { + "edit": { + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "confirmLeave": { + "title": "", + "message": "" + } + }, "oldImport": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, "form": { + "file": { + "label": "", + "invalidError": "" + }, "apps": { - "label": "應用" + "label": "應用", + "avoidDuplicates": { + "label": "", + "description": "" + }, + "onlyImportApps": { + "label": "", + "description": "" + } + }, + "name": { + "label": "" }, "screenSize": { + "label": "", + "description": "", "option": { "sm": "小", "md": "中等", "lg": "大號" } + }, + "sidebarBehavior": { + "label": "", + "description": "", + "option": { + "lastSection": { + "label": "", + "description": "" + }, + "removeItems": { + "label": "", + "description": "" + } + } } } } }, "field": { + "pageTitle": { + "label": "" + }, + "metaTitle": { + "label": "" + }, + "logoImageUrl": { + "label": "" + }, + "faviconImageUrl": { + "label": "" + }, + "backgroundImageUrl": { + "label": "" + }, "backgroundImageAttachment": { - "label": "背景圖片附件" + "label": "背景圖片附件", + "option": { + "fixed": { + "label": "", + "description": "" + }, + "scroll": { + "label": "", + "description": "" + } + } + }, + "backgroundImageRepeat": { + "label": "", + "option": { + "repeat": { + "label": "", + "description": "" + }, + "no-repeat": { + "label": "", + "description": "" + }, + "repeat-x": { + "label": "", + "description": "" + }, + "repeat-y": { + "label": "", + "description": "" + } + } }, "backgroundImageSize": { - "label": "背景圖像大小" + "label": "背景圖像大小", + "option": { + "cover": { + "label": "", + "description": "" + }, + "contain": { + "label": "", + "description": "" + } + } }, "primaryColor": { "label": "主體顏色" @@ -526,20 +1879,37 @@ "secondaryColor": { "label": "輔助顏色" }, + "opacity": { + "label": "" + }, "customCss": { - "description": "此外,只推薦有經驗的使用者使用 CSS 自定義面板" + "label": "", + "description": "此外,只推薦有經驗的使用者使用 CSS 自定義面板", + "customClassesAlert": { + "title": "", + "description": "" + } + }, + "columnCount": { + "label": "" }, "name": { "label": "名稱" }, "isPublic": { - "label": "公開" + "label": "公開", + "description": "" } }, + "content": { + "metaTitle": "" + }, "setting": { + "title": "", "section": { "general": { - "title": "一般" + "title": "一般", + "unrecognizedLink": "" }, "layout": { "title": "顯示布局" @@ -547,11 +1917,24 @@ "background": { "title": "背景" }, + "color": { + "title": "" + }, + "customCss": { + "title": "" + }, "access": { + "title": "", "permission": { "item": { "view": { "label": "查看面板" + }, + "modify": { + "label": "" + }, + "full": { + "label": "" } } } @@ -559,34 +1942,115 @@ "dangerZone": { "title": "危險", "action": { - "delete": { + "rename": { + "label": "", + "description": "", + "button": "", + "modal": { + "title": "" + } + }, + "visibility": { + "label": "", + "description": { + "public": "", + "private": "" + }, + "button": { + "public": "", + "private": "" + }, "confirm": { - "title": "刪除面板" + "public": { + "title": "", + "description": "" + }, + "private": { + "title": "", + "description": "" + } + } + }, + "delete": { + "label": "", + "description": "", + "button": "", + "confirm": { + "title": "刪除面板", + "description": "" } } } } } + }, + "error": { + "noBoard": { + "title": "歡迎來到 Homarr", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { + "metaTitle": "", + "title": { + "morning": "", + "afternoon": "", + "evening": "" + }, + "notFound": { + "title": "", + "text": "" + }, "navbar": { "items": { "home": "首頁", "boards": "面板", "apps": "應用", + "integrations": "", + "searchEngies": "", + "medias": "", "users": { "label": "使用者", "items": { "manage": "管理", - "invites": "邀請" + "invites": "邀請", + "groups": "" } }, "tools": { "label": "工具", "items": { "docker": "Docker", - "api": "API" + "logs": "", + "api": "API", + "tasks": "" } }, "settings": "設定", @@ -594,7 +2058,9 @@ "label": "幫助", "items": { "documentation": "文件", - "discord": "Discord 社群" + "submitIssue": "", + "discord": "Discord 社群", + "sourceCode": "" } }, "about": "關於" @@ -606,30 +2072,48 @@ "board": "面板", "user": "使用者", "invite": "邀請", - "app": "應用" + "integration": "", + "app": "應用", + "group": "" }, "statisticLabel": { - "boards": "面板" + "boards": "面板", + "resources": "", + "authentication": "", + "authorization": "" } }, "board": { "title": "您的面板", "action": { + "new": { + "label": "" + }, + "open": { + "label": "" + }, "settings": { "label": "設定" }, "setHomeBoard": { + "label": "", "badge": { - "label": "首頁" + "label": "首頁", + "tooltip": "" } }, "delete": { "label": "永久刪除", "confirm": { - "title": "刪除面板" + "title": "刪除面板", + "description": "" } } }, + "visibility": { + "public": "", + "private": "" + }, "modal": { "createBoard": { "field": { @@ -640,11 +2124,18 @@ } } }, + "media": { + "includeFromAllUsers": "" + }, "user": { + "back": "", + "fieldsDisabledExternalProvider": "", "setting": { "general": { "title": "一般", "item": { + "language": "", + "board": "", "firstDayOfWeek": "一週的第一天", "accessibility": "無障礙服務" } @@ -660,22 +2151,51 @@ "metaTitle": "管理使用者", "title": "使用者" }, + "edit": { + "metaTitle": "" + }, "create": { "metaTitle": "創建使用者", + "title": "", "step": { + "personalInformation": { + "label": "" + }, "security": { "label": "安全" + }, + "groups": { + "label": "", + "title": "", + "description": "" + }, + "review": { + "label": "" + }, + "completed": { + "title": "" + }, + "error": { + "title": "" } + }, + "action": { + "createAnother": "", + "back": "" } }, "invite": { "title": "管理使用者邀請", "action": { "new": { + "title": "", "description": "過期後,邀請會失效,被邀請者將無法創建帳號" }, "copy": { - "link": "邀請連結" + "title": "", + "description": "", + "link": "邀請連結", + "button": "" }, "delete": { "title": "刪除邀請", @@ -699,50 +2219,217 @@ } }, "group": { + "back": "", "setting": { "general": { - "title": "一般" + "title": "一般", + "owner": "所有者", + "ownerOfGroup": "", + "ownerOfGroupDeleted": "" + }, + "members": { + "title": "", + "search": "", + "notFound": "" + }, + "permissions": { + "title": "", + "form": { + "unsavedChanges": "" + } } } }, "settings": { - "title": "設定" + "title": "設定", + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + }, + "section": { + "analytics": { + "title": "", + "general": { + "title": "", + "text": "" + }, + "widgetData": { + "title": "", + "text": "" + }, + "integrationData": { + "title": "", + "text": "" + }, + "usersData": { + "title": "", + "text": "" + } + }, + "crawlingAndIndexing": { + "title": "", + "warning": "", + "noIndex": { + "title": "", + "text": "" + }, + "noFollow": { + "title": "", + "text": "" + }, + "noTranslate": { + "title": "", + "text": "" + }, + "noSiteLinksSearchBox": { + "title": "", + "text": "" + } + }, + "board": { + "title": "面板", + "homeBoard": { + "label": "", + "description": "" + } + }, + "appearance": { + "title": "外觀", + "defaultColorScheme": { + "label": "", + "options": { + "light": "", + "dark": "" + } + } + }, + "culture": { + "title": "", + "defaultLocale": { + "label": "" + } + } + } }, "tool": { "tasks": { + "title": "", "status": { + "idle": "", "running": "運行中", "error": "錯誤" }, "job": { + "iconsUpdater": { + "label": "" + }, + "analytics": { + "label": "" + }, + "smartHomeEntityState": { + "label": "" + }, + "ping": { + "label": "" + }, "mediaServer": { "label": "媒體服務" }, - "mediaRequests": { - "label": "媒體請求" + "mediaOrganizer": { + "label": "" + }, + "downloads": { + "label": "" + }, + "mediaRequestStats": { + "label": "" + }, + "mediaRequestList": { + "label": "" + }, + "rssFeeds": { + "label": "" + }, + "indexerManager": { + "label": "" + }, + "healthMonitoring": { + "label": "" + }, + "dnsHole": { + "label": "" + }, + "sessionCleanup": { + "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, "api": { "title": "API", + "modal": { + "createApiToken": { + "title": "", + "description": "", + "button": "" + } + }, "tab": { "documentation": { "label": "文件" }, "apiKey": { + "label": "", + "title": "", + "button": { + "createApiToken": "" + }, "table": { "header": { - "id": "ID" + "id": "ID", + "createdBy": "" } } } } } + }, + "about": { + "version": "", + "text": "", + "accordion": { + "contributors": { + "title": "", + "subtitle": "" + }, + "translators": { + "title": "", + "subtitle": "" + }, + "libraries": { + "title": "", + "subtitle": "" + } + } } } }, "docker": { "title": "容器", + "table": { + "updated": "", + "search": "", + "selected": "" + }, "field": { "name": { "label": "名稱" @@ -754,7 +2441,9 @@ "running": "運行中", "paused": "已暫停", "restarting": "正在重啟...", - "removing": "正在刪除..." + "exited": "", + "removing": "正在刪除...", + "dead": "" } }, "containerImage": { @@ -766,27 +2455,102 @@ }, "action": { "start": { - "label": "開始" + "label": "開始", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } }, "stop": { - "label": "停止" + "label": "停止", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } }, "restart": { - "label": "重啟" + "label": "重啟", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } }, "remove": { - "label": "刪除" + "label": "刪除", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "refresh": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } + }, + "error": { + "internalServerError": "" } }, "permission": { + "title": "", + "userSelect": { + "title": "" + }, + "groupSelect": { + "title": "" + }, "tab": { - "user": "使用者" + "user": "使用者", + "group": "", + "inherited": "" }, "field": { "user": { "label": "使用者" + }, + "group": { + "label": "" + }, + "permission": { + "label": "" } + }, + "action": { + "saveUser": "", + "saveGroup": "" } }, "navigationStructure": { @@ -796,17 +2560,31 @@ "label": "面板" }, "integrations": { + "label": "", "edit": { "label": "編輯" + }, + "new": { + "label": "" } }, "search-engines": { + "label": "", + "new": { + "label": "" + }, "edit": { "label": "編輯" } }, + "medias": { + "label": "" + }, "apps": { "label": "應用", + "new": { + "label": "" + }, "edit": { "label": "編輯" } @@ -819,6 +2597,9 @@ "general": "一般", "security": "安全", "board": "面板", + "groups": { + "label": "" + }, "invites": { "label": "邀請" } @@ -827,6 +2608,9 @@ "label": "工具", "docker": { "label": "Docker" + }, + "logs": { + "label": "" } }, "settings": { @@ -838,23 +2622,144 @@ } }, "search": { + "placeholder": "", + "nothingFound": "", + "error": { + "fetch": "" + }, "mode": { "appIntegrationBoard": { + "help": "", "group": { "app": { - "title": "應用" + "title": "應用", + "children": { + "action": { + "open": { + "label": "" + }, + "edit": { + "label": "" + } + }, + "detail": { + "title": "" + } + } }, "board": { - "title": "面板" + "title": "面板", + "children": { + "action": { + "open": { + "label": "" + }, + "homeBoard": { + "label": "" + }, + "settings": { + "label": "" + } + }, + "detail": { + "title": "" + } + } + }, + "integration": { + "title": "" + } + } + }, + "command": { + "help": "", + "group": { + "localCommand": { + "title": "" + }, + "globalCommand": { + "title": "", + "option": { + "colorScheme": { + "light": "", + "dark": "" + }, + "language": { + "label": "", + "children": { + "detail": { + "title": "" + } + } + }, + "newBoard": { + "label": "" + }, + "importBoard": { + "label": "" + }, + "newApp": { + "label": "" + }, + "newIntegration": { + "label": "", + "children": { + "detail": { + "title": "" + } + } + }, + "newUser": { + "label": "" + }, + "newInvite": { + "label": "" + }, + "newGroup": { + "label": "" + } + } } } }, "external": { + "help": "", "group": { "searchEngine": { + "title": "", + "children": { + "action": { + "search": { + "label": "" + } + }, + "detail": { + "title": "" + }, + "searchResults": { + "title": "" + } + }, "option": { + "google": { + "name": "", + "description": "" + }, + "bing": { + "name": "", + "description": "" + }, + "duckduckgo": { + "name": "", + "description": "" + }, "torrent": { - "name": "Torrents" + "name": "Torrents", + "description": "" + }, + "youTube": { + "name": "", + "description": "" } } } @@ -862,12 +2767,18 @@ }, "help": { "group": { + "mode": { + "title": "" + }, "help": { "title": "幫助", "option": { "documentation": { "label": "文件" }, + "submitIssue": { + "label": "" + }, "discord": { "label": "Discord 社群" } @@ -875,16 +2786,67 @@ } } }, + "home": { + "group": { + "local": { + "title": "" + } + } + }, "page": { + "help": "", "group": { "page": { + "title": "", "option": { + "manageHome": { + "label": "" + }, + "manageBoard": { + "label": "" + }, + "manageApp": { + "label": "" + }, + "manageIntegration": { + "label": "" + }, + "manageSearchEngine": { + "label": "" + }, + "manageMedia": { + "label": "" + }, "manageUser": { "label": "管理使用者" }, + "manageInvite": { + "label": "" + }, + "manageGroup": { + "label": "" + }, + "manageDocker": { + "label": "" + }, + "manageApi": { + "label": "" + }, + "manageLog": { + "label": "" + }, + "manageTask": { + "label": "" + }, + "manageSettings": { + "label": "" + }, "about": { "label": "關於" }, + "homeBoard": { + "label": "" + }, "preferences": { "label": "您的偏好設定" } @@ -893,17 +2855,112 @@ } }, "userGroup": { + "help": "", "group": { "user": { - "title": "使用者" + "title": "使用者", + "children": { + "action": { + "detail": { + "label": "" + } + }, + "detail": { + "title": "" + } + } + }, + "group": { + "title": "", + "children": { + "action": { + "detail": { + "label": "" + }, + "manageMember": { + "label": "" + }, + "managePermission": { + "label": "" + } + }, + "detail": { + "title": "" + } + } } } } }, "engine": { + "search": "", "field": { "name": { "label": "名稱" + }, + "short": { + "label": "" + }, + "urlTemplate": { + "label": "" + }, + "description": { + "label": "" + } + }, + "page": { + "list": { + "title": "", + "noResults": { + "title": "", + "action": "" + }, + "interactive": "" + }, + "create": { + "title": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "edit": { + "title": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "configControl": "", + "searchEngineType": { + "generic": "", + "fromIntegration": "" + } + }, + "delete": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/uk.json b/packages/translation/src/lang/uk.json index 880b1893f..250a8b8df 100644 --- a/packages/translation/src/lang/uk.json +++ b/packages/translation/src/lang/uk.json @@ -1,26 +1,131 @@ { + "init": { + "step": { + "start": { + "title": "Ласкаво просимо до Homarr", + "subtitle": "Почнемо з налаштування вашого Homarr.", + "description": "Щоб почати, будь ласка, виберіть спосіб налаштування Вашого Homarr.", + "action": { + "scratch": "Почати з нуля", + "importOldmarr": "Імпорт з Homarr пре-1.0" + } + }, + "import": { + "title": "Імпорт даних", + "subtitle": "Ви можете імпортувати дані з наявного екземпляра Homarr.", + "dropzone": { + "title": "Перетягніть zip-файл сюди або клікніть для пошуку", + "description": "Завантажений zip буде оброблений і ви зможете вибрати що ви хочете імпортувати" + }, + "fileInfo": { + "action": { + "change": "Змінити файл" + } + }, + "importSettings": { + "title": "Імпортувати налаштування", + "description": "Конфігурація імпорту" + }, + "boardSelection": { + "title": "Знайдено {count} дощок", + "description": "Оберіть всі дошки з розміром які ви хочете імпортувати", + "action": { + "selectAll": "Вибрати все", + "unselectAll": "Прибрати всі" + } + }, + "summary": { + "title": "Підсумок імпорту", + "description": "У наведеному нижче розділі ви можете побачити, що буде імпортовано", + "action": { + "import": "Підтвердить імпорт та продовжуйте" + }, + "entities": { + "apps": "Додатки", + "boards": "Дошки", + "integrations": "Інтеграції", + "credentialUsers": "Облікові записи" + } + }, + "tokenModal": { + "title": "Введіть токен імпорту", + "field": { + "token": { + "label": "Токен.", + "description": "Введіть показаний токен імпорту з вашого попереднього екземпляра homarr" + } + }, + "notification": { + "error": { + "title": "Невірний токен", + "message": "Введений вами токен невірний" + } + } + } + }, + "user": { + "title": "Адміністратор", + "subtitle": "Вкажіть облікові дані для вашого адміністратора.", + "notification": { + "success": { + "title": "Користувача створено", + "message": "Користувача успішно створено" + }, + "error": { + "title": "Не вдалося створити користувача" + } + } + }, + "group": { + "title": "Зовнішня група", + "subtitle": "Вкажіть групу, яку слід використовувати для зовнішніх користувачів.", + "form": { + "name": { + "label": "Назва групи", + "description": "Ім'я має відповідати групі адміністраторів зовнішнього провайдера" + } + } + }, + "settings": { + "title": "Налаштування", + "subtitle": "Налаштування сервера." + }, + "finish": { + "title": "Завершити налаштування", + "subtitle": "Все готово!", + "description": "Ви завершили процес налаштування. Тепер ви можете почати використовувати Homarr. Виберіть наступну дію:", + "action": { + "goToBoard": "Перейти на {name} дошку", + "createBoard": "Створіть свою першу дошку", + "inviteUser": "Запросити інших користувачів", + "docs": "Ознайомитися з документацією" + } + } + }, + "backToStart": "На початок" + }, "user": { "title": "Користувачі", "name": "Користувач", "page": { "login": { - "title": "", - "subtitle": "" + "title": "Увійти до облікового запису", + "subtitle": "З поверненням! Будь ласка, введіть свої облікові дані" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "Приєднатися до Homarr", + "subtitle": "Ласкаво просимо до Homarr! Створіть обліковий запис", + "description": "Вас запросив {username}" }, "init": { - "title": "", - "subtitle": "" + "title": "Нова інсталяція Homarr", + "subtitle": "Будь ласка, створіть користувача-адміністратора" } }, "field": { "email": { "label": "Електронна пошта", - "verified": "" + "verified": "Підтверджено" }, "username": { "label": "Логін" @@ -28,46 +133,46 @@ "password": { "label": "Пароль", "requirement": { - "length": "", + "length": "Включає принаймні 8 символів", "lowercase": "Включає малу літеру", "uppercase": "Включає велику літеру", "number": "Включає кількість", - "special": "" + "special": "Включає спеціальні символи" } }, "passwordConfirm": { "label": "Підтвердити пароль" }, "previousPassword": { - "label": "" + "label": "Старий пароль" }, "homeBoard": { - "label": "" + "label": "Домашня дошка" }, "pingIconsEnabled": { - "label": "" + "label": "Використовувати значки для ping" } }, "error": { - "usernameTaken": "" + "usernameTaken": "Це ім'я користувача вже зайнято" }, "action": { "login": { "label": "Логін", - "labelWith": "", + "labelWith": "Увійти через {provider}", "notification": { "success": { - "title": "", - "message": "" + "title": "Вхід успішний", + "message": "Ви ввійшли в систему" }, "error": { - "title": "", - "message": "" + "title": "Не вдалося увійти", + "message": "Помилка входу" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "Забули пароль?", + "description": "Адміністратор може використовувати наступну команду для відновлення пароля:" } }, "register": { @@ -75,81 +180,91 @@ "notification": { "success": { "title": "Обліковий запис створено", - "message": "" + "message": "Увійдіть, щоб продовжити" }, "error": { - "title": "", - "message": "" + "title": "Не вдалося створити обліковий запис", + "message": "Не вдалося створити ваш обліковий запис" } } }, "create": "Створити користувача", "changePassword": { - "label": "", + "label": "Змінити пароль", "notification": { "success": { - "message": "" + "message": "Пароль змінено" }, "error": { - "message": "" + "message": "Не вдалося змінити пароль" } } }, "changeHomeBoard": { "notification": { "success": { - "message": "" + "message": "Домашню дошку змінено" }, "error": { - "message": "" + "message": "Не вдалося змінити домашню дошку" + } + } + }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "Стандартну систему пошуку змінено успішно" + }, + "error": { + "message": "Не вдалося змінити стандартну систему пошуку" } } }, "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "Початок тижня успішно змінено" }, "error": { - "message": "" + "message": "Не вдається змінити перший день тижня" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "Іконки ping перемкнуто успішно" }, "error": { - "message": "" + "message": "Не вдалося перемикнути ping-іконки" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "Змінити зображення", "notification": { "success": { - "message": "" + "message": "Зображення змінено" }, "error": { - "message": "" + "message": "Не вдалося змінити зображення" }, "toLarge": { - "title": "", - "message": "" + "title": "Зображення занадто велике", + "message": "Максимальний розмір зображення {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "Видалити зображення", + "confirm": "Ви впевнені, що хочете видалити зображення?", "notification": { "success": { - "message": "" + "message": "Зображення видалено" }, "error": { - "message": "" + "message": "Не вдалося видалити зображення" } } } @@ -157,50 +272,50 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "Профіль оновлено" }, "error": { - "message": "" + "message": "Не вдалося оновити профіль" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "Видалити користувача назавжди", + "description": "Видаляє цього користувача, включаючи його налаштування. Не буде видалено жодної дошки. Користувач не буде сповіщений.", + "confirm": "Ви впевнені, що хочете видалити користувача {username} разом з налаштуваннями?" }, "select": { - "label": "", - "notFound": "" + "label": "Вибрати користувача", + "notFound": "Користувача не знайдено" }, "transfer": { - "label": "" + "label": "Виберіть нового власника" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "Групи", + "name": "Група", + "search": "Знайти групу", "field": { "name": "Ім’я", - "members": "" + "members": "Учасники" }, "permission": { "admin": { - "title": "", + "title": "Адміністратор", "item": { "admin": { - "label": "", - "description": "" + "label": "Адміністратор", + "description": "Учасники з цим дозволом мають повний доступ до всіх функцій і налаштувань" } } }, "app": { - "title": "", + "title": "Додатки", "item": { "create": { - "label": "", + "label": "Створення додатків", "description": "" }, "use-all": { @@ -328,107 +443,108 @@ "confirm": "", "notification": { "success": { - "message": "" + "message": "Група {group} перенесена до {user}" }, "error": { - "message": "" + "message": "Не вдалося передати право власності" } } }, "addMember": { - "label": "" + "label": "Додати учасника" }, "removeMember": { - "label": "", - "confirm": "" + "label": "Видалити учасника", + "confirm": "Ви впевнені, що хочете видалити {user} з цієї групи?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "Видалити групу", + "description": "Як тільки ви видалите групу, то вже не зможете її відновити. Впевніться у своєму рішенні.", + "confirm": "Ви дійсно бажаєте видалити групу {name}?", "notification": { "success": { - "message": "" + "message": "Групу {name} видалено" }, "error": { - "message": "" + "message": "Не вдалося видалити групу {name}" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "Дозволи збережено", + "message": "Дозволи збережено" }, "error": { - "title": "", - "message": "" + "title": "Дозволи не збережено", + "message": "Дозволи не збережено" } } }, "update": { "notification": { "success": { - "message": "" + "message": "Групу {name} збережено" }, "error": { - "message": "" + "message": "Не вдалося зберегти групу {name}" } } }, "select": { - "label": "", - "notFound": "" + "label": "Виберіть групу", + "notFound": "Груп не знайдено" } } }, "app": { + "search": "", "page": { "list": { "title": "Додатки", "noResults": { - "title": "", - "action": "" + "title": "Поки що немає додатків", + "action": "Створити свій перший додаток" } }, "create": { - "title": "", + "title": "Новий додаток", "notification": { "success": { - "title": "", - "message": "" + "title": "Успішно", + "message": "Додаток створено" }, "error": { - "title": "", - "message": "" + "title": "Не вдалося створити", + "message": "Не вдалося створити додаток" } } }, "edit": { - "title": "", + "title": "Редагувати додаток", "notification": { "success": { - "title": "", - "message": "" + "title": "Зміни застосовано", + "message": "Додаток збережено" }, "error": { - "title": "", - "message": "" + "title": "Не вдалося застосувати зміни", + "message": "Не вдалося зберегти додаток" } } }, "delete": { - "title": "", - "message": "", + "title": "Видалити додаток", + "message": "Ви дійсно бажаєте видалити додаток {name}?", "notification": { "success": { - "title": "", - "message": "" + "title": "Успішно видалено", + "message": "Додаток видалено" }, "error": { - "title": "", - "message": "" + "title": "Не вдалося видалити", + "message": "Неможливо видалити додаток" } } } @@ -438,46 +554,46 @@ "label": "Ім’я" }, "description": { - "label": "" + "label": "Опис" }, "url": { - "label": "" + "label": "URL-адреса" } }, "action": { "select": { - "label": "", - "notFound": "" + "label": "Оберіть додаток", + "notFound": "Додатків не знайдено" } } }, "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "Інтеграції", + "search": "Пошук інтеграцій", "noResults": { - "title": "" + "title": "Тут ще немає інтеграції" } }, "create": { - "title": "", + "title": "Нова інтеграція з {name}", "notification": { "success": { - "title": "", - "message": "" + "title": "Успішно створено", + "message": "Інтеграцію створено" }, "error": { - "title": "", - "message": "" + "title": "Не вдалося створити", + "message": "Не вдалося створити інтеграцію" } } }, "edit": { - "title": "", + "title": "Редагування інтеграцію {name}", "notification": { "success": { - "title": "", + "title": "Зміни застосовано", "message": "" }, "error": { @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,19 +708,23 @@ "secrets": { "title": "", "lastUpdated": "", - "secureNotice": "", + "notSet": { + "label": "", + "tooltip": "Обов’язковий ключ ще не був встановлений" + }, + "secureNotice": "Цей секрет неможливо буде побачити після створення", "reset": { - "title": "", - "message": "" + "title": "Скинути секрет", + "message": "Ви впевнені, що хочете скинути цей секрет?" }, "noSecretsRequired": { - "segmentTitle": "", - "text": "" + "segmentTitle": "Немає секретів", + "text": "Для цієї інтеграції не потрібні секрети" }, "kind": { "username": { "label": "Логін", - "newLabel": "" + "newLabel": "Нове ім'я користувача" }, "apiKey": { "label": "", @@ -608,7 +732,7 @@ }, "password": { "label": "Пароль", - "newLabel": "" + "newLabel": "Новий пароль" } } }, @@ -661,12 +785,12 @@ "error": "Помилка", "action": { "add": "Додати", - "apply": "", + "apply": "Застосувати", "backToOverview": "", "create": "Створити", "edit": "Редагувати", "import": "", - "insert": "", + "insert": "Вставити", "remove": "Видалити", "save": "Зберегти", "saveChanges": "Зберегти зміни", @@ -678,6 +802,7 @@ "previous": "Попередній", "next": "Далі", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Повторіть спробу", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Логін", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Небезпечна зона", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -908,13 +1043,13 @@ "label": "" }, "layout": { - "label": "", + "label": "Макет", "option": { "row": { - "label": "" + "label": "Горизонтальний" }, "column": { - "label": "" + "label": "Вертикальний" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "", "dnsQueriesToday": "Запити за сьогодні", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1021,7 +1157,7 @@ "label": "" }, "timezone": { - "label": "", + "label": "Часовий пояс", "description": "" }, "showDate": { @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Блокнот", "description": "", @@ -1081,7 +1236,7 @@ }, "align": { "left": "Ліворуч.", - "center": "", + "center": "Центр", "right": "Так." }, "popover": { @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Ваш браузер не підтримує iframe. Будь ласка, оновіть свій браузер." } }, @@ -1136,7 +1292,7 @@ "description": "", "option": { "entityId": { - "label": "" + "label": "Ідентифікатор об'єкта" }, "displayName": { "label": "" @@ -1154,10 +1310,10 @@ "description": "", "option": { "displayName": { - "label": "" + "label": "Відображати ім'я" }, "automationId": { - "label": "" + "label": "Ідентифікатор автоматизації" } }, "spotlightAction": { @@ -1227,15 +1383,15 @@ } }, "indexerManager": { - "name": "", + "name": "Статус менеджера індексування", "description": "", "option": { "openIndexerSiteInNewTab": { "label": "" } }, - "title": "", - "testAll": "", + "title": "Менеджер індексації", + "testAll": "Перевірте все", "error": { "internalServerError": "" } @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1389,7 +1547,7 @@ }, "added": { "columnTitle": "", - "detailsTitle": "" + "detailsTitle": "Дата додавання" }, "category": { "columnTitle": "", @@ -1417,7 +1575,7 @@ "detailsTitle": "" }, "ratio": { - "columnTitle": "", + "columnTitle": "Співвідношення", "detailsTitle": "" }, "received": { @@ -1450,8 +1608,8 @@ } }, "states": { - "downloading": "", - "queued": "", + "downloading": "Завантаження", + "queued": "У черзі", "paused": "Призупинено", "completed": "Завершено", "failed": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "Вигляд за замовчуванням" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "Робітники", + "queue": "Черга", + "statistics": "Статистика" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "У черзі", + "status": { + "healthy": "Здоровий", + "unhealthy": "Нездоровий" + } + }, + "panel": { + "statistics": { + "empty": "Пусто", + "transcodes": "Перекодує", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "Кодеки", + "videoContainers": "Контейнери", + "videoResolutions": "Роздільна здатність" + }, + "workers": { + "empty": "Пусто", + "table": { + "file": "Файл", + "eta": "Залишилося", + "progress": "Прогрес", + "transcode": "Перекодувати", + "healthCheck": "" + } + }, + "queue": { + "empty": "Пусто", + "table": { + "file": "Файл", + "size": "Розмір", + "transcode": "Перекодувати", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Малий", "md": "Середній", @@ -1647,7 +1879,7 @@ "label": "" }, "backgroundImageAttachment": { - "label": "", + "label": "Прикріплене фонове зображення", "option": { "fixed": { "label": "", @@ -1681,7 +1913,7 @@ } }, "backgroundImageSize": { - "label": "", + "label": "Розмір фонового зображення", "option": { "cover": { "label": "", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Видалити назавжди", "confirm": { @@ -1923,13 +2198,20 @@ "title": "Загальне", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Перший день тижня", "accessibility": "Доступність" } }, "security": { - "title": "" + "title": "Безпека" }, "board": { "title": "Дошки" @@ -1950,7 +2232,7 @@ "label": "" }, "security": { - "label": "" + "label": "Безпека" }, "groups": { "label": "", @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Загальне", - "owner": "", + "owner": "Власник", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Дошки", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Вигляд", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Помилка" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2206,7 +2505,7 @@ } }, "docker": { - "title": "", + "title": "Контейнери", "table": { "updated": "", "search": "", @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2374,7 +2692,7 @@ "label": "Створити" }, "general": "Загальне", - "security": "", + "security": "Безпека", "board": "Дошки", "groups": { "label": "" @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/vi.json b/packages/translation/src/lang/vi.json index 9edf37d76..9921b7ffc 100644 --- a/packages/translation/src/lang/vi.json +++ b/packages/translation/src/lang/vi.json @@ -1,4 +1,109 @@ { + "init": { + "step": { + "start": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "scratch": "", + "importOldmarr": "" + } + }, + "import": { + "title": "", + "subtitle": "", + "dropzone": { + "title": "", + "description": "" + }, + "fileInfo": { + "action": { + "change": "" + } + }, + "importSettings": { + "title": "", + "description": "" + }, + "boardSelection": { + "title": "", + "description": "", + "action": { + "selectAll": "", + "unselectAll": "" + } + }, + "summary": { + "title": "", + "description": "", + "action": { + "import": "" + }, + "entities": { + "apps": "Ứng dụng", + "boards": "Bảng", + "integrations": "", + "credentialUsers": "" + } + }, + "tokenModal": { + "title": "", + "field": { + "token": { + "label": "Mã thông báo", + "description": "" + } + }, + "notification": { + "error": { + "title": "", + "message": "" + } + } + } + }, + "user": { + "title": "", + "subtitle": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "" + } + } + }, + "group": { + "title": "", + "subtitle": "", + "form": { + "name": { + "label": "", + "description": "" + } + } + }, + "settings": { + "title": "Cài đặt", + "subtitle": "" + }, + "finish": { + "title": "", + "subtitle": "", + "description": "", + "action": { + "goToBoard": "", + "createBoard": "", + "inviteUser": "", + "docs": "" + } + } + }, + "backToStart": "" + }, "user": { "title": "Người dùng", "name": "Người dùng", @@ -105,6 +210,16 @@ } } }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "" + }, + "error": { + "message": "" + } + } + }, "changeFirstDayOfWeek": { "notification": { "success": { @@ -197,7 +312,7 @@ } }, "app": { - "title": "", + "title": "Ứng dụng", "item": { "create": { "label": "", @@ -384,6 +499,7 @@ } }, "app": { + "search": "", "page": { "list": { "title": "Ứng dụng", @@ -507,6 +623,10 @@ }, "url": { "label": "" + }, + "attemptSearchEngineCreation": { + "label": "", + "description": "" } }, "action": { @@ -588,6 +708,10 @@ "secrets": { "title": "", "lastUpdated": "", + "notSet": { + "label": "", + "tooltip": "" + }, "secureNotice": "", "reset": { "title": "", @@ -678,6 +802,7 @@ "previous": "Trước", "next": "Kế tiếp", "checkoutDocs": "", + "checkLogs": "", "tryAgain": "Thử lại", "loading": "" }, @@ -686,6 +811,12 @@ "label": "", "header": "" }, + "colorScheme": { + "options": { + "light": "", + "dark": "" + } + }, "information": { "min": "", "max": "", @@ -733,7 +864,8 @@ "logout": "", "login": "Đăng nhập", "homeBoard": "", - "loggedOut": "" + "loggedOut": "", + "updateAvailable": "" } }, "dangerZone": "Khu vực nguy hiểm", @@ -765,8 +897,10 @@ "passwordRequirements": "", "boardAlreadyExists": "", "invalidFileType": "", + "invalidFileName": "", "fileTooLarge": "", - "invalidConfiguration": "" + "invalidConfiguration": "", + "groupNameTaken": "" } } } @@ -833,6 +967,7 @@ }, "create": { "title": "", + "search": "", "addToBoard": "" }, "moveResize": { @@ -908,13 +1043,13 @@ "label": "" }, "layout": { - "label": "", + "label": "Bố cục", "option": { "row": { - "label": "" + "label": "Nằm ngang" }, "column": { - "label": "" + "label": "Thẳng đứng" }, "grid": { "label": "" @@ -958,7 +1093,8 @@ "adsBlockedTodayPercentage": "Đã chặn hôm nay", "dnsQueriesToday": "Truy vấn hôm nay", "domainsBeingBlocked": "" - } + }, + "domainsTooltip": "" }, "dnsHoleControls": { "name": "", @@ -1033,6 +1169,25 @@ } } }, + "minecraftServerStatus": { + "name": "", + "description": "", + "option": { + "title": { + "label": "" + }, + "domain": { + "label": "" + }, + "isBedrockServer": { + "label": "" + } + }, + "status": { + "online": "", + "offline": "" + } + }, "notebook": { "name": "Ghi chú", "description": "", @@ -1128,6 +1283,7 @@ }, "error": { "noUrl": "", + "unsupportedProtocol": "", "noBrowerSupport": "Trình duyệt của bạn không hỗ trợ iframe. Vui lòng cập nhật trình duyệt của bạn." } }, @@ -1308,9 +1464,6 @@ "description": "" }, "error": { - "action": { - "logs": "" - }, "noIntegration": "", "noData": "" }, @@ -1342,7 +1495,12 @@ "mediaServer": { "name": "", "description": "", - "option": {} + "option": {}, + "items": { + "user": "", + "name": "", + "id": "" + } }, "downloads": { "name": "", @@ -1528,6 +1686,65 @@ } } }, + "mediaTranscoding": { + "name": "", + "description": "", + "option": { + "defaultView": { + "label": "" + }, + "queuePageSize": { + "label": "" + } + }, + "tab": { + "workers": "", + "queue": "Chờ", + "statistics": "" + }, + "currentIndex": "", + "healthCheck": { + "title": "", + "queued": "", + "status": { + "healthy": "", + "unhealthy": "" + } + }, + "panel": { + "statistics": { + "empty": "Trống", + "transcodes": "", + "transcodesCount": "", + "healthChecksCount": "", + "filesCount": "", + "savedSpace": "", + "healthChecks": "", + "videoCodecs": "", + "videoContainers": "", + "videoResolutions": "" + }, + "workers": { + "empty": "Trống", + "table": { + "file": "", + "eta": "Thời gian dự kiến", + "progress": "Tiến độ", + "transcode": "", + "healthCheck": "" + } + }, + "queue": { + "empty": "Trống", + "table": { + "file": "", + "size": "Kích cỡ", + "transcode": "", + "healthCheck": "" + } + } + } + }, "rssFeed": { "name": "", "description": "", @@ -1558,6 +1775,20 @@ }, "board": { "action": { + "duplicate": { + "title": "", + "message": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, "edit": { "notification": { "success": { @@ -1607,6 +1838,7 @@ }, "screenSize": { "label": "", + "description": "", "option": { "sm": "Bé nhỏ", "md": "Trung bình", @@ -1803,6 +2035,38 @@ } } } + }, + "error": { + "noBoard": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "notFound": { + "title": "", + "description": "", + "link": "", + "notice": "" + }, + "homeBoard": { + "title": "", + "admin": { + "description": "", + "link": "", + "notice": "" + }, + "user": { + "description": "", + "link": "", + "notice": "" + }, + "anonymous": { + "description": "", + "link": "", + "notice": "" + } + } } }, "management": { @@ -1838,6 +2102,7 @@ "docker": "", "logs": "", "api": "", + "certificates": "", "tasks": "" } }, @@ -1890,6 +2155,16 @@ "tooltip": "" } }, + "setMobileHomeBoard": { + "label": "", + "badge": { + "label": "", + "tooltip": "" + } + }, + "duplicate": { + "label": "" + }, "delete": { "label": "Xóa vĩnh viễn", "confirm": { @@ -1923,7 +2198,14 @@ "title": "Chung", "item": { "language": "", - "board": "", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "", "firstDayOfWeek": "Ngày đầu tiên trong tuần", "accessibility": "Trợ năng" } @@ -2011,7 +2293,7 @@ "setting": { "general": { "title": "Chung", - "owner": "", + "owner": "Chủ", "ownerOfGroup": "", "ownerOfGroupDeleted": "" }, @@ -2079,14 +2361,22 @@ } }, "board": { - "title": "", + "title": "Bảng", "homeBoard": { + "label": "", + "mobileLabel": "", + "description": "" + } + }, + "search": { + "title": "", + "defaultSearchEngine": { "label": "", "description": "" } }, "appearance": { - "title": "", + "title": "Hiển thị", "defaultColorScheme": { "label": "", "options": { @@ -2112,6 +2402,9 @@ "error": "Lỗi" }, "job": { + "minecraftServerStatus": { + "label": "" + }, "iconsUpdater": { "label": "" }, @@ -2153,6 +2446,12 @@ }, "sessionCleanup": { "label": "" + }, + "updateChecker": { + "label": "" + }, + "mediaTranscoding": { + "label": "" } } }, @@ -2300,7 +2599,26 @@ "message": "" } } + }, + "addToHomarr": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + }, + "modal": { + "title": "" + } } + }, + "error": { + "internalServerError": "" } }, "permission": { @@ -2390,6 +2708,9 @@ }, "logs": { "label": "" + }, + "certificates": { + "label": "" } }, "settings": { @@ -2436,6 +2757,9 @@ "homeBoard": { "label": "" }, + "mobileBoard": { + "label": "" + }, "settings": { "label": "" } @@ -2501,6 +2825,11 @@ } } }, + "media": { + "requestMovie": "", + "requestSeries": "", + "openIn": "" + }, "external": { "help": "", "group": { @@ -2567,6 +2896,24 @@ }, "home": { "group": { + "search": { + "title": "", + "option": { + "other": { + "label": "" + }, + "no-default": { + "label": "", + "description": "" + }, + "search": { + "label": "" + }, + "from-integration": { + "description": "" + } + } + }, "local": { "title": "" } @@ -2741,6 +3088,63 @@ } } } + }, + "media": { + "request": { + "modal": { + "title": "", + "table": { + "header": { + "season": "", + "episodes": "" + } + }, + "button": { + "send": "" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { + "label": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } + }, + "remove": { + "label": "", + "confirm": "", + "notification": { + "success": { + "title": "", + "message": "" + }, + "error": { + "title": "", + "message": "" + } + } } } } diff --git a/packages/translation/src/lang/zh.json b/packages/translation/src/lang/zh.json index 5ec0e4e15..09d632016 100644 --- a/packages/translation/src/lang/zh.json +++ b/packages/translation/src/lang/zh.json @@ -1,155 +1,270 @@ { + "init": { + "step": { + "start": { + "title": "歡迎使用 Homarr", + "subtitle": "讓我們開始設定 Homarr", + "description": "請選擇設定 Homarr 方式", + "action": { + "scratch": "重新開始", + "importOldmarr": "從 1.0 版本的 Homarr 匯入設定" + } + }, + "import": { + "title": "匯入數據", + "subtitle": "從現有的 Homarr 匯入數據", + "dropzone": { + "title": "將 ZIP 壓縮檔拖曳至此處或點擊瀏覽", + "description": "上傳的壓縮檔將被處理,您可以選擇要匯入的內容" + }, + "fileInfo": { + "action": { + "change": "更改檔案" + } + }, + "importSettings": { + "title": "匯入設定", + "description": "設定匯入方式" + }, + "boardSelection": { + "title": "找到 {count} 個面板", + "description": "選擇要匯入的面板", + "action": { + "selectAll": "選擇全部", + "unselectAll": "取消全選" + } + }, + "summary": { + "title": "匯入概況", + "description": "於下方的概況中,可以看到即將匯入的內容", + "action": { + "import": "確認匯入並繼續" + }, + "entities": { + "apps": "應用程式", + "boards": "面板", + "integrations": "集成", + "credentialUsers": "使用者憑證" + } + }, + "tokenModal": { + "title": "輸入匯入密鑰", + "field": { + "token": { + "label": "密鑰", + "description": "輸入之前 Homarr 中顯示導入之密鑰匙" + } + }, + "notification": { + "error": { + "title": "無效密鑰", + "message": "輸入的密鑰無效" + } + } + } + }, + "user": { + "title": "管理員", + "subtitle": "指定管理員的使用者憑證", + "notification": { + "success": { + "title": "創建使用者", + "message": "使用者已成功創建" + }, + "error": { + "title": "使用者創建失敗" + } + } + }, + "group": { + "title": "外部使用者", + "subtitle": "指定用於外部使用者的用戶組", + "form": { + "name": { + "label": "用戶組名稱", + "description": "名稱必須與外部提供者的管理員匹配" + } + } + }, + "settings": { + "title": "設定", + "subtitle": "設定伺服器的設定" + }, + "finish": { + "title": "設定完成", + "subtitle": "已設定完成", + "description": "已成功完成設定,開始使用 Homarr,請選擇下一步操作", + "action": { + "goToBoard": "進入 {name} 面板", + "createBoard": "創建第一個面板", + "inviteUser": "邀請其他使用者", + "docs": "閱讀說明書" + } + } + }, + "backToStart": "返回起點" + }, "user": { - "title": "", - "name": "", + "title": "使用者", + "name": "使用者", "page": { "login": { - "title": "", - "subtitle": "" + "title": "登入帳戶", + "subtitle": "歡迎回來!請輸入憑證" }, "invite": { - "title": "", - "subtitle": "", - "description": "" + "title": "加入 Homarr", + "subtitle": "歡迎來到 Homarr!請創建帳戶", + "description": "您受到 {username} 的邀請" }, "init": { - "title": "", - "subtitle": "" + "title": "新建 Homarr 安裝", + "subtitle": "請創建初始管理員" } }, "field": { "email": { - "label": "", - "verified": "" + "label": "E-Mail", + "verified": "已驗證" }, "username": { - "label": "" + "label": "使用者名稱" }, "password": { - "label": "", + "label": "密碼", "requirement": { - "length": "", - "lowercase": "", - "uppercase": "", - "number": "", - "special": "" + "length": "至少包含 8 個字符", + "lowercase": "包含小寫字母", + "uppercase": "包含大寫字母", + "number": "包含數字", + "special": "包含特殊符號" } }, "passwordConfirm": { - "label": "" + "label": "確認密碼" }, "previousPassword": { - "label": "" + "label": "過去的密碼" }, "homeBoard": { - "label": "" + "label": "主面板" }, "pingIconsEnabled": { - "label": "" + "label": "為 Pings 使用 icon" } }, "error": { - "usernameTaken": "" + "usernameTaken": "使用者名稱已存在" }, "action": { "login": { - "label": "", - "labelWith": "", + "label": "登入", + "labelWith": "使用 {provider} 登入", "notification": { "success": { - "title": "", - "message": "" + "title": "登入成功", + "message": "您已登入" }, "error": { - "title": "", - "message": "" + "title": "登入失敗", + "message": "您已登入失敗" } }, "forgotPassword": { - "label": "", - "description": "" + "label": "忘記密碼嗎?", + "description": "管理員可以使用以下命令重設密碼" } }, "register": { - "label": "", + "label": "創建帳戶", "notification": { "success": { - "title": "", - "message": "" + "title": "帳戶已創建", + "message": "請登入後繼續" }, "error": { - "title": "", - "message": "" + "title": "帳戶創建失敗", + "message": "無法創建帳戶" } } }, - "create": "", + "create": "創建使用者", "changePassword": { - "label": "", + "label": "更改密碼", "notification": { "success": { - "message": "" + "message": "密碼已成功更改" }, "error": { - "message": "" + "message": "無法更改密碼" } } }, "changeHomeBoard": { "notification": { "success": { - "message": "" + "message": "主面板已更改成功" }, "error": { - "message": "" + "message": "無法更改主面板" + } + } + }, + "changeDefaultSearchEngine": { + "notification": { + "success": { + "message": "預設搜尋引擎已變更成功" + }, + "error": { + "message": "預設搜尋引擎無法變更" } } }, "changeFirstDayOfWeek": { "notification": { "success": { - "message": "" + "message": "成功編輯一周的第一天" }, "error": { - "message": "" + "message": "無法編輯一周的第一天" } } }, "changePingIconsEnabled": { "notification": { "success": { - "message": "" + "message": "Pings icon 切換成功" }, "error": { - "message": "" + "message": "無法切換 Pings icon" } } }, "manageAvatar": { "changeImage": { - "label": "", + "label": "更改圖案", "notification": { "success": { - "message": "" + "message": "圖案編輯成功" }, "error": { - "message": "" + "message": "無法更改圖案" }, "toLarge": { - "title": "", - "message": "" + "title": "圖案太大", + "message": "最大圖案尺寸為 {size}" } } }, "removeImage": { - "label": "", - "confirm": "", + "label": "移除圖案", + "confirm": "確認要移除圖案嗎?", "notification": { "success": { - "message": "" + "message": "圖案移除成功" }, "error": { - "message": "" + "message": "無法移除圖案" } } } @@ -157,616 +272,635 @@ "editProfile": { "notification": { "success": { - "message": "" + "message": "數據更新成功" }, "error": { - "message": "" + "message": "數據無法更新" } } }, "delete": { - "label": "", - "description": "", - "confirm": "" + "label": "永久移除使用者", + "description": "移除此使用者,包括其偏好設定,這不會移除任何面板,且用戶不會收到通知", + "confirm": "你確認移除使用者 {username} 及其偏好設定嗎?" }, "select": { - "label": "", - "notFound": "" + "label": "選擇使用者", + "notFound": "使用者不存在" }, "transfer": { - "label": "" + "label": "選擇新的所有者" } } }, "group": { - "title": "", - "name": "", - "search": "", + "title": "用戶組", + "name": "組", + "search": "尋找用戶組", "field": { - "name": "", - "members": "" + "name": "名稱", + "members": "成員" }, "permission": { "admin": { - "title": "", + "title": "管理員", "item": { "admin": { - "label": "", - "description": "" + "label": "管理員", + "description": "擁有此權限的使用者可完全訪問全部功能和設定" } } }, "app": { - "title": "", + "title": "應用程式", "item": { "create": { - "label": "", - "description": "" + "label": "創建應用程式", + "description": "允許成員創建應用程式" }, "use-all": { - "label": "", - "description": "" + "label": "使用全部應用程式", + "description": "允許成員編輯全部應用程式" }, "modify-all": { - "label": "", - "description": "" + "label": "編輯全部應用程式", + "description": "允許成員編輯全部應用程式" }, "full-all": { - "label": "", - "description": "" + "label": "完整應用程式權限", + "description": "允許成員編輯全部應用程式" } } }, "board": { - "title": "", + "title": "面板", "item": { "create": { - "label": "", - "description": "" + "label": "創建面板", + "description": "允許成員創建面板" }, "view-all": { - "label": "", - "description": "" + "label": "查看全部面板", + "description": "允許成員查看全部面板" }, "modify-all": { - "label": "", - "description": "" + "label": "編輯全部面板", + "description": "允許成員編輯全部面板,不包括訪問控制和危險區域" }, "full-all": { - "label": "", - "description": "" + "label": "完整面板權限", + "description": "允許成員查看、編輯和移除全部面板,包括訪問控制和危險區域" } } }, "integration": { - "title": "", + "title": "集成", "item": { "create": { - "label": "", - "description": "" + "label": "創建集成", + "description": "允許成員創建集成" }, "use-all": { - "label": "", - "description": "" + "label": "使用全部集成", + "description": "允許成員將任何應用程式新增至他們的面板" }, "interact-all": { - "label": "", - "description": "" + "label": "與任何集成進行互動", + "description": "允許成員與任何集成進行交互" }, "full-all": { - "label": "", - "description": "" + "label": "完整的集成訪問權限", + "description": "允許成員管理、使用並與任何集成交互" } } }, "media": { - "title": "", + "title": "多媒體", "item": { "upload": { - "label": "", - "description": "" + "label": "上傳多媒體", + "description": "允許成員上傳多媒體" }, "view-all": { - "label": "", - "description": "" + "label": "查看全部多媒體", + "description": "允許成員查看全部多媒體" }, "full-all": { - "label": "", - "description": "" + "label": "圖案移除成功", + "description": "允許使用者管理、使用、移除任何應用" } } }, "other": { - "title": "", + "title": "其他", "item": { "view-logs": { - "label": "", - "description": "" + "label": "檢視 Logs", + "description": "允許使用者檢視 Logs" } } }, "search-engine": { - "title": "", + "title": "搜尋引擎", "item": { "create": { - "label": "", - "description": "" + "label": "創建搜尋引擎", + "description": "允許使用者創建搜尋引擎" }, "modify-all": { - "label": "", - "description": "" + "label": "編輯全部搜尋引擎", + "description": "允許使用者編輯全部搜尋引擎" }, "full-all": { - "label": "", - "description": "" + "label": "完整搜尋引擎的訪問權限", + "description": "允許使用者管理、移除任何搜尋引擎" } } } }, "memberNotice": { - "mixed": "", - "external": "" + "mixed": "部分使用者來自外部提供者,無法在此處管理", + "external": "全部成員都來自外部提供者,無法在此處管理" }, "reservedNotice": { - "message": "" + "message": "此用戶組保留供系統使用並限制部分操作 " }, "action": { "create": { - "label": "", + "label": "創建用戶組", "notification": { "success": { - "message": "" + "message": "用戶組已創建成功" }, "error": { - "message": "" + "message": "用戶組創建失敗" } } }, "transfer": { - "label": "", - "description": "", - "confirm": "", + "label": "移轉所有權", + "description": "將此用戶組的所有權移轉至其他用戶", + "confirm": "確認將用戶組 {name} 的所有權移轉至 {username} 嗎?", "notification": { "success": { - "message": "" + "message": "將用戶組 {group} 的所有權移轉至 {user} 成功" }, "error": { - "message": "" + "message": "無法移轉所有權" } } }, "addMember": { - "label": "" + "label": "新增成員" }, "removeMember": { - "label": "", - "confirm": "" + "label": "移除成員", + "confirm": "確認將 {user} 移除此用戶組嗎?" }, "delete": { - "label": "", - "description": "", - "confirm": "", + "label": "移除用戶組", + "description": "用戶組一旦刪除將無法恢復,請謹慎操作", + "confirm": "確認移除用戶組 {name} 嗎?", "notification": { "success": { - "message": "" + "message": "移除用戶組 {name} 成功" }, "error": { - "message": "" + "message": "無法移除用戶組 {name}" } } }, "changePermissions": { "notification": { "success": { - "title": "", - "message": "" + "title": "權限已儲存", + "message": "權限已儲存成功" }, "error": { - "title": "", - "message": "" + "title": "權限未儲存", + "message": "權限尚未儲存" } } }, "update": { "notification": { "success": { - "message": "" + "message": "用戶組 {name} 已儲存成功" }, "error": { - "message": "" + "message": "無法儲存用戶組 {name}" } } }, "select": { - "label": "", - "notFound": "" + "label": "選擇用戶組", + "notFound": "用戶組不存在" } } }, "app": { + "search": "尋找應用程式", "page": { "list": { - "title": "", + "title": "應用程式", "noResults": { - "title": "", - "action": "" + "title": "尚無應用程式", + "action": "創建第一個應用程式" } }, "create": { - "title": "", + "title": "創建應用程式", "notification": { "success": { - "title": "", - "message": "" + "title": "創建成功", + "message": "應用程式已創建成功" }, "error": { - "title": "", - "message": "" + "title": "創建失敗", + "message": "應用程式無法創建" } } }, "edit": { - "title": "", + "title": "編輯應用程式", "notification": { "success": { - "title": "", - "message": "" + "title": "應用程式編輯成功", + "message": "應用程式儲存成功" }, "error": { - "title": "", - "message": "" + "title": "無法更改", + "message": "應用程式無法儲存" } } }, "delete": { - "title": "", - "message": "", + "title": "移除應用程式", + "message": "確認移除此應用程式 {name} 嗎?", "notification": { "success": { - "title": "", - "message": "" + "title": "移除成功", + "message": "應用程式已移除成功" }, "error": { - "title": "", - "message": "" + "title": "移除失敗", + "message": "無法移除應用程式" } } } }, "field": { "name": { - "label": "" + "label": "名稱" }, "description": { - "label": "" + "label": "描述" }, "url": { - "label": "" + "label": "網址" } }, "action": { "select": { - "label": "", - "notFound": "" + "label": "選擇應用程式", + "notFound": "應用程式不存在" } } }, "integration": { "page": { "list": { - "title": "", - "search": "", + "title": "集成", + "search": "選擇集成", "noResults": { - "title": "" + "title": "尚無集成" } }, "create": { - "title": "", + "title": "創建 {name} 集成", "notification": { "success": { - "title": "", - "message": "" + "title": "創建成功", + "message": "集成創建成功" }, "error": { - "title": "", - "message": "" + "title": "創建失敗", + "message": "此集成無法被創建" } } }, "edit": { - "title": "", + "title": "編輯 {name} 集成", "notification": { "success": { - "title": "", - "message": "" + "title": "編輯成功", + "message": "集成已儲存成功" }, "error": { - "title": "", - "message": "" + "title": "無法應用變更", + "message": "集成無法被儲存" } } }, "delete": { - "title": "", - "message": "", + "title": "移除集成", + "message": "確認移除集成 {name} 嗎?", "notification": { "success": { - "title": "", - "message": "" + "title": "移除成功", + "message": "集成移除成功" }, "error": { - "title": "", - "message": "" + "title": "移除失敗", + "message": "集成移除失敗" } } } }, "field": { "name": { - "label": "" + "label": "名稱" }, "url": { - "label": "" + "label": "網址" + }, + "attemptSearchEngineCreation": { + "label": "創建搜尋引擎", + "description": "集成 {kind} 可以與搜尋引擎共同使用,勾選此選項可自動設定搜尋引擎" } }, "action": { - "create": "" + "create": "創建集成" }, "testConnection": { "action": { - "create": "", - "edit": "" + "create": "測試連線並創建", + "edit": "測試連線並儲存" }, - "alertNotice": "", + "alertNotice": "成功建立連線後儲存按鈕將啟用", "notification": { "success": { - "title": "", - "message": "" + "title": "連線成功", + "message": "已成功建立連線" }, "invalidUrl": { - "title": "", - "message": "" + "title": "無效網址", + "message": "此網址無效" }, "secretNotDefined": { - "title": "", - "message": "" + "title": "缺少憑證", + "message": "並非全部憑證都已提供" }, "invalidCredentials": { - "title": "", - "message": "" + "title": "無效憑證", + "message": "憑證無效" }, "commonError": { - "title": "", - "message": "" + "title": "連線失敗", + "message": "無法建立連線" }, "badRequest": { - "title": "", - "message": "" + "title": "錯誤請求", + "message": "請求格式不正確" }, "unauthorized": { - "title": "", - "message": "" + "title": "未授權", + "message": "可能是錯誤的憑證" }, "forbidden": { - "title": "", - "message": "" + "title": "禁止", + "message": "可能缺少權限" }, "notFound": { - "title": "", - "message": "" + "title": "不存在", + "message": "可能是錯誤的網址或路徑" }, "internalServerError": { - "title": "", - "message": "" + "title": "伺服器內部錯誤", + "message": "伺服器遇到錯誤" }, "serviceUnavailable": { - "title": "", - "message": "" + "title": "服務暫時不可用", + "message": "伺服器當前不可用" }, "connectionAborted": { - "title": "", - "message": "" + "title": "連線終止", + "message": "連線被終止" }, "domainNotFound": { - "title": "", - "message": "" + "title": "網域不存在", + "message": "網域不存在" }, "connectionRefused": { - "title": "", - "message": "" + "title": "連線拒絕", + "message": "連線被拒絕" }, "invalidJson": { - "title": "", - "message": "" + "title": "無效的 JSON", + "message": "無效的 JSON 回應" }, "wrongPath": { - "title": "", - "message": "" + "title": "路徑錯誤", + "message": "路徑可能是錯誤" } } }, "secrets": { - "title": "", - "lastUpdated": "", - "secureNotice": "", + "title": "密鑰", + "lastUpdated": "最後更新於 {date}", + "notSet": { + "label": "未設定值", + "tooltip": "尚未設定此必填的密鑰" + }, + "secureNotice": "創建後無法再次取得此密鑰", "reset": { - "title": "", - "message": "" + "title": "重設密鑰", + "message": "確認重設密鑰嗎?" }, "noSecretsRequired": { - "segmentTitle": "", - "text": "" + "segmentTitle": "無密鑰", + "text": "此集成無需密鑰" }, "kind": { "username": { - "label": "", - "newLabel": "" + "label": "使用者名稱", + "newLabel": "新使用者名稱" }, "apiKey": { - "label": "", - "newLabel": "" + "label": "API Key", + "newLabel": "新 API Key" }, "password": { - "label": "", - "newLabel": "" + "label": "密碼", + "newLabel": "新密碼" } } }, "permission": { - "use": "", - "interact": "", - "full": "" + "use": "選擇項目中的集成", + "interact": "與集成進行互動", + "full": "完整的集成訪問權限" } }, "media": { - "plural": "", - "search": "", + "plural": "多媒體", + "search": "尋找多媒體", "field": { - "name": "", - "size": "", - "creator": "" + "name": "名稱", + "size": "大小", + "creator": "創建者" }, "action": { "upload": { - "label": "", - "file": "", + "label": "上傳多媒體", + "file": "選擇檔案", "notification": { "success": { - "message": "" + "message": "多媒體已上傳成功" }, "error": { - "message": "" + "message": "多媒體無法上傳" } } }, "delete": { - "label": "", - "description": "", + "label": "移除多媒體", + "description": "確認移除多媒體 嗎?", "notification": { "success": { - "message": "" + "message": "多媒體已移除成功" }, "error": { - "message": "" + "message": "多媒體無法移除" } } }, "copy": { - "label": "" + "label": "複製網址" } } }, "common": { - "beta": "", - "error": "", + "beta": "測試版", + "error": "錯誤", "action": { - "add": "", - "apply": "", - "backToOverview": "", - "create": "", - "edit": "", - "import": "", - "insert": "", - "remove": "", - "save": "", - "saveChanges": "", - "cancel": "", - "delete": "", - "discard": "", - "confirm": "", - "continue": "", - "previous": "", - "next": "", - "checkoutDocs": "", - "tryAgain": "", - "loading": "" + "add": "新增", + "apply": "應用", + "backToOverview": "返回總覽", + "create": "創建", + "edit": "編輯", + "import": "匯入", + "insert": "插入", + "remove": "移除", + "save": "儲存", + "saveChanges": "儲存變更", + "cancel": "取消", + "delete": "移除", + "discard": "丟棄", + "confirm": "確認", + "continue": "繼續", + "previous": "上一步", + "next": "下一步", + "checkoutDocs": "查閱說明書", + "checkLogs": "檢查 Logs 以取得更多詳情", + "tryAgain": "重試", + "loading": "正在讀取" }, - "here": "", + "here": "此處", "iconPicker": { - "label": "", - "header": "" + "label": "Icon 網址", + "header": "輸入名稱或物件來篩選 icons,Homarr 會自動搜尋 {countIcons}" + }, + "colorScheme": { + "options": { + "light": "日間", + "dark": "暗黑" + } }, "information": { - "min": "", - "max": "", - "days": "", - "hours": "", - "minutes": "" + "min": "最小", + "max": "最大", + "days": "天", + "hours": "時", + "minutes": "分" }, "notification": { "create": { - "success": "", - "error": "" + "success": "創建成功", + "error": "創建失敗" }, "delete": { - "success": "", - "error": "" + "success": "移除成功", + "error": "移除失敗" }, "update": { - "success": "", - "error": "" + "success": "應用變更成功", + "error": "無法應用變更" }, "transfer": { - "success": "", - "error": "" + "success": "移轉成功", + "error": "移轉失敗" } }, "multiSelect": { - "placeholder": "" + "placeholder": "選擇一個或多個值" }, "multiText": { - "placeholder": "", - "addLabel": "" + "placeholder": "新增更多值", + "addLabel": "新增 {value}" }, "select": { - "placeholder": "", + "placeholder": "選擇值", "badge": { - "recommended": "" + "recommended": "建議" } }, "userAvatar": { "menu": { - "switchToDarkMode": "", - "switchToLightMode": "", - "management": "", - "preferences": "", - "logout": "", - "login": "", - "homeBoard": "", - "loggedOut": "" + "switchToDarkMode": "切換至暗黑模式", + "switchToLightMode": "切換至日間模式", + "management": "管理中心", + "preferences": "偏好設定", + "logout": "登出", + "login": "登入", + "homeBoard": "首頁", + "loggedOut": "已登出", + "updateAvailable": "{countUpdates} 可用更新:{tag}" } }, - "dangerZone": "", - "noResults": "", + "dangerZone": "危險區域", + "noResults": "未找到結果", "preview": { - "show": "", - "hide": "" + "show": "顯示預覽", + "hide": "隱藏預覽" }, "zod": { "errors": { - "default": "", - "required": "", + "default": "此欄位無效", + "required": "此欄位為必填", "string": { - "startsWith": "", - "endsWith": "", - "includes": "", - "invalidEmail": "" + "startsWith": "此欄位必須以 {startsWith} 開頭", + "endsWith": "此欄位必須以 {endsWith} 結尾", + "includes": "此欄位必須包含 {includes}", + "invalidEmail": "此欄位必須是有效的 E-Mail" }, "tooSmall": { - "string": "", - "number": "" + "string": "此欄位必須至少為 {minimum} 個字符", + "number": "此欄位必須大於或等於 {minimum}" }, "tooBig": { - "string": "", - "number": "" + "string": "此欄位長度不得超過 {maximum}", + "number": "此欄位必須小於或等於 {maximum}" }, "custom": { - "passwordsDoNotMatch": "", - "passwordRequirements": "", - "boardAlreadyExists": "", - "invalidFileType": "", - "fileTooLarge": "", - "invalidConfiguration": "" + "passwordsDoNotMatch": "兩次輸入的密碼不一致", + "passwordRequirements": "密碼不符合要求", + "boardAlreadyExists": "此面板名稱已存在", + "invalidFileType": "無效的檔案類型,例如 {expected}", + "invalidFileName": "", + "fileTooLarge": "檔案太大,最大大小為 {maxSize}", + "invalidConfiguration": "無效設定", + "groupNameTaken": "用戶組名稱已存在" } } } @@ -774,856 +908,954 @@ "section": { "dynamic": { "action": { - "create": "", - "remove": "" + "create": "創建動態區段", + "remove": "移除動態區段" }, "remove": { - "title": "", - "message": "" + "title": "移除動態區段", + "message": "確認要移除此動態區段嗎?項目將移動到父區段的相同位置" } }, "category": { "field": { "name": { - "label": "" + "label": "名稱" } }, "action": { - "create": "", - "edit": "", - "remove": "", - "moveUp": "", - "moveDown": "", - "createAbove": "", - "createBelow": "" + "create": "創建分類", + "edit": "移除分類", + "remove": "移除分類", + "moveUp": "上移", + "moveDown": "下移", + "createAbove": "新分類之上", + "createBelow": "新分類之下" }, "create": { - "title": "", - "submit": "" + "title": "創建分類", + "submit": "創建分類" }, "remove": { - "title": "", - "message": "" + "title": "移除分類", + "message": "確認移除分類 {name} 嗎?" }, "edit": { - "title": "", - "submit": "" + "title": "重新命名分類", + "submit": "重新命名分類" }, "menu": { "label": { - "create": "", - "changePosition": "" + "create": "創建分類", + "changePosition": "變更位置" } } } }, "item": { "action": { - "create": "", - "import": "", - "edit": "", - "moveResize": "", - "duplicate": "", - "remove": "" + "create": "創建項目", + "import": "匯入項目", + "edit": "編輯項目", + "moveResize": "移動 / 調整大小項目", + "duplicate": "複製項目", + "remove": "移除項目" }, "menu": { "label": { - "settings": "" + "settings": "設定" } }, "create": { - "title": "", - "addToBoard": "" + "title": "選擇要新增的項目", + "search": "篩選項目", + "addToBoard": "新增至面板" }, "moveResize": { - "title": "", + "title": "移動 / 調整大小項目", "field": { "width": { - "label": "" + "label": "寬度" }, "height": { - "label": "" + "label": "高度" }, "xOffset": { - "label": "" + "label": "X 軸" }, "yOffset": { - "label": "" + "label": "Y 軸" } } }, "edit": { - "title": "", + "title": "編輯項目", "advancedOptions": { - "label": "", - "title": "" + "label": "進階選項", + "title": "進階項目選項" }, "field": { "integrations": { - "label": "" + "label": "集成" }, "customCssClasses": { - "label": "" + "label": "自定義 CSS html" } } }, "remove": { - "title": "", - "message": "" + "title": "移除項目", + "message": "確認要移除此項目嗎?" } }, "widget": { "app": { - "name": "", - "description": "", + "name": "應用程式", + "description": "將應用程式新增至面板中", "option": { "appId": { - "label": "" + "label": "選擇應用程式" }, "openInNewTab": { - "label": "" + "label": "於新分頁中開啟" }, "showTitle": { - "label": "" + "label": "顯示應用程式名稱" }, "showDescriptionTooltip": { - "label": "" + "label": "顯示描述提示" }, "pingEnabled": { - "label": "" + "label": "啟用簡單的 Ping" } }, "error": { "notFound": { - "label": "", - "tooltip": "" + "label": "無應用程式", + "tooltip": "未選擇有效的應用程式" } } }, "bookmarks": { - "name": "", - "description": "", + "name": "書籤", + "description": "顯示多個應用程式鏈結", "option": { "title": { - "label": "" + "label": "標題" }, "layout": { - "label": "", + "label": "顯示布局", "option": { "row": { - "label": "" + "label": "橫向" }, "column": { - "label": "" + "label": "垂直" }, "grid": { - "label": "" + "label": "網格" } } }, "items": { - "label": "", - "add": "" + "label": "書籤", + "add": "新增書籤" } } }, "dnsHoleSummary": { - "name": "", - "description": "", + "name": "DNS Hole 概況", + "description": "顯示 DNS Hole 的概況", "option": { "layout": { - "label": "", + "label": "顯示布局", "option": { "row": { - "label": "" + "label": "橫向" }, "column": { - "label": "" + "label": "垂直" }, "grid": { - "label": "" + "label": "網格" } } }, "usePiHoleColors": { - "label": "" + "label": "使用 Pi-Hole 顏色" } }, "error": { - "internalServerError": "", - "integrationsDisconnected": "" + "internalServerError": "取得 DNS Hole 概況失敗", + "integrationsDisconnected": "無可用的數據,所有集成已斷線" }, "data": { - "adsBlockedToday": "", - "adsBlockedTodayPercentage": "", - "dnsQueriesToday": "", - "domainsBeingBlocked": "" - } + "adsBlockedToday": "今日封鎖", + "adsBlockedTodayPercentage": "今日封鎖", + "dnsQueriesToday": "今日查詢", + "domainsBeingBlocked": "黑名單的網域" + }, + "domainsTooltip": "由於多個集成,Homarr 無法精準計算被阻擋的網域數量" }, "dnsHoleControls": { - "name": "", - "description": "", + "name": "DNS Hole 控制", + "description": "從面板控制 Pi-Hole 或 AdGuard", "option": { "layout": { - "label": "", + "label": "顯示布局", "option": { "row": { - "label": "" + "label": "橫向" }, "column": { - "label": "" + "label": "垂直" }, "grid": { - "label": "" + "label": "網格" } } }, "showToggleAllButtons": { - "label": "" + "label": "顯示全部按鈕" } }, "error": { - "internalServerError": "" + "internalServerError": "無法控制 DNS Hole" }, "controls": { - "enableAll": "", - "disableAll": "", - "setTimer": "", - "set": "", - "enabled": "", - "disabled": "", - "processing": "", - "disconnected": "", - "hours": "", - "minutes": "", - "unlimited": "" + "enableAll": "啟用全部", + "disableAll": "停用全部", + "setTimer": "設定計時", + "set": "設定", + "enabled": "已啟用", + "disabled": "已停用", + "processing": "處理中", + "disconnected": "斷線", + "hours": "時", + "minutes": "分", + "unlimited": "留空表示無限制" } }, "clock": { - "name": "", - "description": "", + "name": "日期和時間", + "description": "顯示當前日期和時間", "option": { "customTitleToggle": { - "label": "", - "description": "" + "label": "自定義標題/城市顯示\n", + "description": "在時鐘上顯示自定義的標題或城市/國家名稱" }, "customTitle": { - "label": "" + "label": "標題" }, "is24HourFormat": { - "label": "", - "description": "" + "label": "24 小時制", + "description": "使用 24 小時制替代 12 小時制" }, "showSeconds": { - "label": "" + "label": "顯示秒數" }, "useCustomTimezone": { - "label": "" + "label": "使用固定時區" }, "timezone": { - "label": "", - "description": "" + "label": "時區", + "description": "選擇遵循 IANA 標準的時區" }, "showDate": { - "label": "" + "label": "顯示日期" }, "dateFormat": { - "label": "", - "description": "" + "label": "日期格式", + "description": "日期應該是什麼樣式" } } }, + "minecraftServerStatus": { + "name": "Minecraft 伺服器狀態", + "description": "顯示 Minecraft 伺服器狀態", + "option": { + "title": { + "label": "標題" + }, + "domain": { + "label": "伺服器地址" + }, + "isBedrockServer": { + "label": "Bedrock 伺服器" + } + }, + "status": { + "online": "在線", + "offline": "離線" + } + }, "notebook": { - "name": "", - "description": "", + "name": "筆記", + "description": "支持 Markdown 的簡單筆記小工具", "option": { "showToolbar": { - "label": "" + "label": "顯示幫助寫下 Markdown 的工具欄" }, "allowReadOnlyCheck": { - "label": "" + "label": "允許於唯讀模式中檢查" }, "content": { - "label": "" + "label": "筆記的內容" } }, "controls": { - "bold": "", - "italic": "", - "strikethrough": "", - "underline": "", - "colorText": "", - "colorHighlight": "", - "code": "", - "clear": "", - "heading": "", - "align": "", - "blockquote": "", - "horizontalLine": "", - "bulletList": "", - "orderedList": "", - "checkList": "", - "increaseIndent": "", - "decreaseIndent": "", - "link": "", - "unlink": "", - "image": "", - "addTable": "", - "deleteTable": "", - "colorCell": "", - "mergeCell": "", - "addColumnLeft": "", - "addColumnRight": "", - "deleteColumn": "", - "addRowTop": "", - "addRowBelow": "", - "deleteRow": "" + "bold": "粗體", + "italic": "斜體", + "strikethrough": "刪除線", + "underline": "底線", + "colorText": "文字顏色", + "colorHighlight": "彩色高亮文字", + "code": "代碼", + "clear": "清除格式", + "heading": "標題 {level}", + "align": "對齊文字:{position}", + "blockquote": "引用", + "horizontalLine": "橫線", + "bulletList": "符號列表", + "orderedList": "順序列表", + "checkList": "檢查列表", + "increaseIndent": "增加縮進", + "decreaseIndent": "減少縮進", + "link": "鏈結", + "unlink": "移除鏈結", + "image": "崁入圖案", + "addTable": "新增表格", + "deleteTable": "移除表格", + "colorCell": "單元格顏色", + "mergeCell": "切換單元格合併", + "addColumnLeft": "於前方新增列", + "addColumnRight": "於後方新增列", + "deleteColumn": "移除整列", + "addRowTop": "於前方新增行", + "addRowBelow": "於後方新增行", + "deleteRow": "移除整行" }, "align": { - "left": "", - "center": "", - "right": "" + "left": "左方", + "center": "置中", + "right": "右方" }, "popover": { - "clearColor": "", - "source": "", - "widthPlaceholder": "", - "columns": "", - "rows": "", - "width": "", - "height": "" + "clearColor": "清除顏色", + "source": "來源", + "widthPlaceholder": "百分比或像素值", + "columns": "列數", + "rows": "行數", + "width": "寬度", + "height": "高度" } }, "iframe": { - "name": "", - "description": "", + "name": "iFrame", + "description": "崁入網路上的任何內容,某些網站可能限制訪問", "option": { "embedUrl": { - "label": "" + "label": "崁入網址" }, "allowFullScreen": { - "label": "" + "label": "允許全螢幕" }, "allowTransparency": { - "label": "" + "label": "允取透明" }, "allowScrolling": { - "label": "" + "label": "允許滾動" }, "allowPayment": { - "label": "" + "label": "允許支付" }, "allowAutoPlay": { - "label": "" + "label": "允許自動播放" }, "allowMicrophone": { - "label": "" + "label": "允許麥克風" }, "allowCamera": { - "label": "" + "label": "允許攝影機" }, "allowGeolocation": { - "label": "" + "label": "允許地址位置" } }, "error": { - "noUrl": "", - "noBrowerSupport": "" + "noUrl": "未提供 iFrame 網址", + "unsupportedProtocol": "提供的網址使用了不支援的協議,請使用以下之一:{supportedProtocols}", + "noBrowerSupport": "此瀏覽器不支持 iFrame,請使用其他瀏覽器" } }, "smartHome-entityState": { - "name": "", - "description": "", + "name": "設備狀態", + "description": "顯示設備狀態並可選切換", "option": { "entityId": { - "label": "" + "label": "設備 ID" }, "displayName": { - "label": "" + "label": "顯示名稱" }, "entityUnit": { - "label": "" + "label": "顯示單位" }, "clickable": { - "label": "" + "label": "可點擊" } } }, "smartHome-executeAutomation": { - "name": "", - "description": "", + "name": "執行自動化", + "description": "一鍵觸發自動化", "option": { "displayName": { - "label": "" + "label": "顯示名稱" }, "automationId": { - "label": "" + "label": "自動化 ID" } }, "spotlightAction": { - "run": "" + "run": "執行 {name}" } }, "calendar": { - "name": "", - "description": "", + "name": "日曆", + "description": "在特定的相對時間範圍內,將來自您的集成事件以日曆視圖顯示", "option": { "releaseType": { - "label": "", + "label": "Radarr 發行類型", "options": { - "inCinemas": "", - "digitalRelease": "", - "physicalRelease": "" + "inCinemas": "上映中", + "digitalRelease": "數位發行", + "physicalRelease": "實體發行" } }, "filterPastMonths": { - "label": "" + "label": "開始於" }, "filterFutureMonths": { - "label": "" + "label": "終止於" } } }, "weather": { - "name": "", - "description": "", + "name": "天氣", + "description": "顯示指定位置的當前天氣狀況", "option": { "isFormatFahrenheit": { - "label": "" + "label": "華氏溫度" }, "location": { - "label": "" + "label": "天氣位置" }, "showCity": { - "label": "" + "label": "顯示城市" }, "hasForecast": { - "label": "" + "label": "顯示預報" }, "forecastDayCount": { - "label": "", - "description": "" + "label": "預報天數", + "description": "當小工具寬度不足時,顯示的天數將減少" }, "dateFormat": { - "label": "", - "description": "" + "label": "日期格式", + "description": "日期應該是什麼樣式" } }, "kind": { - "clear": "", - "mainlyClear": "", - "fog": "", - "drizzle": "", - "freezingDrizzle": "", - "rain": "", - "freezingRain": "", - "snowFall": "", - "snowGrains": "", - "rainShowers": "", - "snowShowers": "", - "thunderstorm": "", - "thunderstormWithHail": "", - "unknown": "" + "clear": "晴朗", + "mainlyClear": "大多晴朗", + "fog": "起霧", + "drizzle": "細雨", + "freezingDrizzle": "凍細雨", + "rain": "雨天", + "freezingRain": "凍雨天", + "snowFall": "降雪", + "snowGrains": "冰霰", + "rainShowers": "陣雨", + "snowShowers": "陣雪", + "thunderstorm": "雷暴", + "thunderstormWithHail": "雷暴伴冰雹", + "unknown": "未知" } }, "indexerManager": { - "name": "", - "description": "", + "name": "索引器管理狀態", + "description": "索引器狀態", "option": { "openIndexerSiteInNewTab": { - "label": "" + "label": "於新分頁中開啟索引器站點" } }, - "title": "", - "testAll": "", + "title": "索引器管理器", + "testAll": "測試全部", "error": { - "internalServerError": "" + "internalServerError": "無法取得索引器狀態" } }, "healthMonitoring": { - "name": "", - "description": "", + "name": "系統健康監測", + "description": "顯示系統運行狀態", "option": { "fahrenheit": { - "label": "" + "label": "處理器溫度" }, "cpu": { - "label": "" + "label": "顯示處理器訊息" }, "memory": { - "label": "" + "label": "顯示記憶體訊息" }, "fileSystem": { - "label": "" + "label": "顯示檔案系統訊息" } }, "popover": { - "information": "", - "processor": "", - "memory": "", - "memoryAvailable": "", - "version": "", - "uptime": "", - "loadAverage": "", - "minute": "", - "minutes": "", - "used": "", - "available": "", - "lastSeen": "" + "information": "訊息", + "processor": "處理器:{cpuModelName}", + "memory": "記憶體:{memory} GiB", + "memoryAvailable": "可用:{memoryAvailable} Gib ({percent}%)", + "version": "版本:{version}", + "uptime": "運行時間:{months} 月,{days} 天,{hours} 時,{minutes} 分", + "loadAverage": "平均負載:", + "minute": "1 分鐘", + "minutes": "{count} 分鐘", + "used": "已使用", + "available": "可用", + "lastSeen": "最後狀態更新:{lastSeen}" }, "memory": {}, "error": { - "internalServerError": "" + "internalServerError": "取得健康狀態失敗" } }, "common": { "location": { - "query": "", - "latitude": "", - "longitude": "", - "disabledTooltip": "", - "unknownLocation": "", - "search": "", + "query": "城市 / 郵遞區號", + "latitude": "緯度", + "longitude": "經度", + "disabledTooltip": "請輸入城市或郵遞區號", + "unknownLocation": "未知", + "search": "未找到集成", "table": { "header": { - "city": "", - "country": "", - "coordinates": "", - "population": "" + "city": "城市", + "country": "國家", + "coordinates": "座標", + "population": "人口" }, "action": { - "select": "" + "select": "選擇 {city},{countryCode}" }, "population": { - "fallback": "" + "fallback": "未知" } } }, "integration": { - "noData": "", - "description": "" + "noData": "未找到集成", + "description": "點擊 創建新的集成" }, "app": { - "noData": "", - "description": "" + "noData": "未找到應用程式", + "description": "點擊 創建新的應用程式" }, "error": { - "action": { - "logs": "" - }, - "noIntegration": "", - "noData": "" + "noIntegration": "未選擇集成", + "noData": "無可用的集成數據" }, "option": {} }, "video": { - "name": "", - "description": "", + "name": "串流影音", + "description": "崁入來自攝影機或網站的影音", "option": { "feedUrl": { - "label": "" + "label": "訂閱網址" }, "hasAutoPlay": { - "label": "", - "description": "" + "label": "自動播放", + "description": "由於瀏覽器限制,自動播放僅在靜音時有效" }, "isMuted": { - "label": "" + "label": "靜音" }, "hasControls": { - "label": "" + "label": "顯示控制" } }, "error": { - "noUrl": "", - "forYoutubeUseIframe": "" + "noUrl": "無提供影音網址", + "forYoutubeUseIframe": "Youtube 影音使用 iFrame 選項" } }, "mediaServer": { - "name": "", - "description": "", - "option": {} + "name": "當前多媒體伺服器串流", + "description": "顯示當前多媒體伺服器的串流", + "option": {}, + "items": { + "user": "使用者", + "name": "名稱", + "id": "ID" + } }, "downloads": { - "name": "", - "description": "", + "name": "下載器", + "description": "允許查看和管理來自 Torrent 和 Usenet 的下載器", "option": { "columns": { - "label": "" + "label": "顯示的列" }, "enableRowSorting": { - "label": "" + "label": "啟用項目排序" }, "defaultSort": { - "label": "" + "label": "默認排序列" }, "descendingDefaultSort": { - "label": "" + "label": "倒序" }, "showCompletedUsenet": { - "label": "" + "label": "顯示標記為已完成的 Usenet 項目" }, "showCompletedTorrent": { - "label": "" + "label": "顯示標記為已完成的 Torrent 項目" }, "activeTorrentThreshold": { - "label": "" + "label": "隱藏在此閥值下完成的 Torrent (kiB/s)" }, "categoryFilter": { - "label": "" + "label": "要過濾的分類/標籤" }, "filterIsWhitelist": { - "label": "" + "label": "以白名單篩選" }, "applyFilterToRatio": { - "label": "" + "label": "使用篩選器來計算速率" } }, "errors": { - "noColumns": "", - "noCommunications": "" + "noColumns": "於項目中選擇列", + "noCommunications": "無法從集成中加載數據" }, "items": { "actions": { - "columnTitle": "" + "columnTitle": "控制" }, "added": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "已新增", + "detailsTitle": "日期已新增" }, "category": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "擴展的", + "detailsTitle": "分類 (額外訊息)" }, "downSpeed": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "下載", + "detailsTitle": "下載速度" }, "index": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "#", + "detailsTitle": "下載器中的當前索引" }, "id": { - "columnTitle": "" + "columnTitle": "ID" }, "integration": { - "columnTitle": "" + "columnTitle": "集成" }, "name": { - "columnTitle": "" + "columnTitle": "工作名稱" }, "progress": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "進度", + "detailsTitle": "下載進度" }, "ratio": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "分享率", + "detailsTitle": "Torrent 速率 (接收/發送)" }, "received": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "總下載", + "detailsTitle": "總下載量" }, "sent": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "總上傳", + "detailsTitle": "總上傳量" }, "size": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "檔案大小", + "detailsTitle": "選擇/檔案的總大小" }, "state": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "狀態", + "detailsTitle": "工作狀態" }, "time": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "完成時間", + "detailsTitle": "剩餘完成時間" }, "type": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "類型", + "detailsTitle": "下載器類型" }, "upSpeed": { - "columnTitle": "", - "detailsTitle": "" + "columnTitle": "上傳", + "detailsTitle": "上傳速度" } }, "states": { - "downloading": "", - "queued": "", - "paused": "", - "completed": "", - "failed": "", - "processing": "", - "leeching": "", - "stalled": "", - "unknown": "", - "seeding": "" + "downloading": "下載中", + "queued": "隊列中", + "paused": "已暫停", + "completed": "已完成", + "failed": "已失敗", + "processing": "進行中", + "leeching": "吸血中", + "stalled": "已暫停", + "unknown": "未知", + "seeding": "做種中" }, "actions": { "clients": { - "modalTitle": "", - "pause": "", - "resume": "" + "modalTitle": "下載器列表", + "pause": "暫停全部下載器/項目", + "resume": "恢復全部下載器/項目" }, "client": { - "pause": "", - "resume": "" + "pause": "暫停下載器", + "resume": "恢復下載器" }, "item": { - "pause": "", - "resume": "", + "pause": "暫停項目", + "resume": "恢復項目", "delete": { - "title": "", - "modalTitle": "", - "entry": "", - "entryAndFiles": "" + "title": "移除項目", + "modalTitle": "確認要移除此工作嗎?", + "entry": "移除項目", + "entryAndFiles": "移除項目和檔案" } } }, - "globalRatio": "" + "globalRatio": "全局速率" }, "mediaRequests-requestList": { - "name": "", - "description": "", + "name": "多媒體請求列表", + "description": "查看 Overrseerr 或 Jellyseerr 中所有多媒體請求列表", "option": { "linksTargetNewTab": { - "label": "" + "label": "於新分頁中開啟鏈結" } }, "pending": { - "approve": "", - "approving": "", - "decline": "" + "approve": "批准請求", + "approving": "正在批准請求中 ...", + "decline": "拒絕請求" }, "availability": { - "unknown": "", - "pending": "", - "processing": "", - "partiallyAvailable": "", - "available": "" + "unknown": "未知", + "pending": "等待處理中", + "processing": "處理中", + "partiallyAvailable": "部分", + "available": "待定" }, - "toBeDetermined": "" + "toBeDetermined": "多媒體請求狀態" }, "mediaRequests-requestStats": { - "name": "", - "description": "", + "name": "多媒體請求狀態", + "description": "多媒體請求統計", "option": {}, "titles": { "stats": { - "main": "", - "approved": "", - "pending": "", - "processing": "", - "declined": "", - "available": "", - "tv": "", - "movie": "", - "total": "" + "main": "多媒體狀態", + "approved": "已批准", + "pending": "等待批准", + "processing": "處理中", + "declined": "已拒絕", + "available": "已可用", + "tv": "電視劇請求", + "movie": "電影請求", + "total": "總計" }, "users": { - "main": "", - "requests": "" + "main": "使用者排行", + "requests": "請求" + } + } + }, + "mediaTranscoding": { + "name": "多媒體轉碼", + "description": "多媒體轉碼統計,當前隊列和工作狀態", + "option": { + "defaultView": { + "label": "預設瀏覽" + }, + "queuePageSize": { + "label": "隊列頁面大小" + } + }, + "tab": { + "workers": "工作中", + "queue": "隊列", + "statistics": "統計" + }, + "currentIndex": "{total} 的 {start} - {end}", + "healthCheck": { + "title": "健康檢查", + "queued": "隊列中", + "status": { + "healthy": "健康", + "unhealthy": "不良" + } + }, + "panel": { + "statistics": { + "empty": "空", + "transcodes": "轉碼", + "transcodesCount": "轉碼:{value}", + "healthChecksCount": "健康檢查:{value}", + "filesCount": "檔案:{value}", + "savedSpace": "節省空間:{value}", + "healthChecks": "健康檢查", + "videoCodecs": "編碼", + "videoContainers": "容器", + "videoResolutions": "解析度" + }, + "workers": { + "empty": "空", + "table": { + "file": "檔案", + "eta": "剩餘時間", + "progress": "進度", + "transcode": "轉碼", + "healthCheck": "健康檢查" + } + }, + "queue": { + "empty": "空", + "table": { + "file": "檔案", + "size": "大小", + "transcode": "轉碼", + "healthCheck": "健康檢查" + } } } }, "rssFeed": { - "name": "", - "description": "", + "name": "RSS 訂閱", + "description": "顯示一個或多個 RSS、ATOM、JSON 源", "option": { "feedUrls": { - "label": "" + "label": "Feed 網址" }, "enableRtl": { - "label": "" + "label": "啟用 RTL" }, "textLinesClamp": { - "label": "" + "label": "描述行數限制" }, "maximumAmountPosts": { - "label": "" + "label": "帖子數量限制" } } } }, "widgetPreview": { "toggle": { - "enabled": "", - "disabled": "" + "enabled": "啟用編輯模式", + "disabled": "停用編輯模式" }, "dimensions": { - "title": "" + "title": "編輯尺寸" } }, "board": { "action": { + "duplicate": { + "title": "複製面板", + "message": "這將複製看板 {name} 及其所有內容。如果小工具引用了無法使用的集成,它們將被移除", + "notification": { + "success": { + "title": "面板已複製", + "message": "面板已複製成功" + }, + "error": { + "title": "面板無法複製", + "message": "此面板無法被複製" + } + } + }, "edit": { "notification": { "success": { - "title": "", - "message": "" + "title": "成功應用編輯", + "message": "面板儲存成功" }, "error": { - "title": "", - "message": "" + "title": "無法應用編輯", + "message": "面板無法儲存" } }, "confirmLeave": { - "title": "", - "message": "" + "title": "未儲存編輯", + "message": "尚未保存編輯,確認要離開嗎?" } }, "oldImport": { - "label": "", + "label": "從 1.0.0 之前的 Homarr 匯入", "notification": { "success": { - "title": "", - "message": "" + "title": "匯入成功", + "message": "面板匯入成功" }, "error": { - "title": "", - "message": "" + "title": "匯入失敗", + "message": "無法匯入面板,請查閱 Logs 以取得更多詳情" } }, "form": { "file": { - "label": "", - "invalidError": "" + "label": "選擇 JSON 檔案", + "invalidError": "無效的設定檔案" }, "apps": { - "label": "", + "label": "應用程式", "avoidDuplicates": { - "label": "", - "description": "" + "label": "避免重複", + "description": "忽略已存在具有相同鏈結的應用程式" }, "onlyImportApps": { - "label": "", - "description": "" + "label": "僅匯入應用程式", + "description": "僅新增應用程式,面板需要手動重新創建" } }, "name": { - "label": "" + "label": "面板名稱" }, "screenSize": { - "label": "", + "label": "螢幕大小", + "description": "在 1.0 之前的版本中,有三種不同的模式,因此可以根據螢幕大小選擇列的數量", "option": { - "sm": "", - "md": "", - "lg": "" + "sm": "小號", + "md": "中等", + "lg": "大號" } }, "sidebarBehavior": { - "label": "", - "description": "", + "label": "側邊欄行為", + "description": "側邊欄在 1.0 中被移除了,你可以選擇該怎麼處理其中的項目", "option": { "lastSection": { - "label": "", - "description": "" + "label": "最後區段", + "description": "側邊欄將顯示在最後區段的下方" }, "removeItems": { - "label": "", - "description": "" + "label": "移除項目", + "description": "側邊欄中包含的項目將被移除" } } } @@ -1632,553 +1864,620 @@ }, "field": { "pageTitle": { - "label": "" + "label": "頁面標題" }, "metaTitle": { - "label": "" + "label": "Meta 標題" }, "logoImageUrl": { - "label": "" + "label": "Logo 圖案網址" }, "faviconImageUrl": { - "label": "" + "label": "Favicon 圖案網址" }, "backgroundImageUrl": { - "label": "" + "label": "背景圖案網址" }, "backgroundImageAttachment": { - "label": "", + "label": "背景圖案附件", "option": { "fixed": { - "label": "", - "description": "" + "label": "固定", + "description": "背景保持不變" }, "scroll": { - "label": "", - "description": "" + "label": "滾動", + "description": "用滑鼠滾動背景" } } }, "backgroundImageRepeat": { - "label": "", + "label": "背景圖案重複", "option": { "repeat": { - "label": "", - "description": "" + "label": "重複", + "description": "為了覆蓋整個背景圖案區域,將會重複使用來填充整個畫面" }, "no-repeat": { - "label": "", - "description": "" + "label": "不重複", + "description": "圖案不重複,無法填充整個畫面" }, "repeat-x": { - "label": "", - "description": "" + "label": "水平重複", + "description": "與 \"重複\" 相同,但僅於水平軸上" }, "repeat-y": { - "label": "", - "description": "" + "label": "垂直重複", + "description": "與 \"重複\" 相同,但僅於垂直軸上" } } }, "backgroundImageSize": { - "label": "", + "label": "背景圖案大小", "option": { "cover": { - "label": "", - "description": "" + "label": "封面", + "description": "通過剪裁多餘的畫面,將圖案縮放至盡可能小以覆蓋整個畫面" }, "contain": { - "label": "", - "description": "" + "label": "包含", + "description": "將圖案縮放於容器中,但不剪裁或拉伸圖案" } } }, "primaryColor": { - "label": "" + "label": "主體色" }, "secondaryColor": { - "label": "" + "label": "輔助色" }, "opacity": { - "label": "" + "label": "不透明度" }, "customCss": { - "label": "", - "description": "", + "label": "自定義此面板 CSS html", + "description": "僅推薦有經驗的使用者使用 CSS html", "customClassesAlert": { - "title": "", - "description": "" + "title": "自定義類別", + "description": "可以於每個項目中的進階選項中新增自定義類別至面板,並於自定義 CSS html 中使用他們" } }, "columnCount": { - "label": "" + "label": "列數" }, "name": { - "label": "" + "label": "名稱" }, "isPublic": { - "label": "", - "description": "" + "label": "公開", + "description": "每個人皆可訪問公共面板,即使沒有帳號" } }, "content": { - "metaTitle": "" + "metaTitle": "{boardName} 面板" }, "setting": { - "title": "", + "title": "{boardName} 面板設定", "section": { "general": { - "title": "", - "unrecognizedLink": "" + "title": "一般", + "unrecognizedLink": "提供的鏈結未被識別,無法預覽,但可能仍然有效" }, "layout": { - "title": "" + "title": "顯示布局" }, "background": { - "title": "" + "title": "背景" }, "color": { - "title": "" + "title": "配色" }, "customCss": { - "title": "" + "title": "自定義 CSS html" }, "access": { - "title": "", + "title": "訪問控制", "permission": { "item": { "view": { - "label": "" + "label": "查看面板" }, "modify": { - "label": "" + "label": "編輯面板" }, "full": { - "label": "" + "label": "完全訪問" } } } }, "dangerZone": { - "title": "", + "title": "危險區域", "action": { "rename": { - "label": "", - "description": "", - "button": "", + "label": "重新命名面板", + "description": "更改面板可見性", + "button": "更改名稱", "modal": { - "title": "" + "title": "重新命名面板" } }, "visibility": { - "label": "", + "label": "更改面板可見性", "description": { - "public": "", - "private": "" + "public": "此面板目前為公開狀態", + "private": "此面板目前為私人狀態" }, "button": { - "public": "", - "private": "" + "public": "設定私人", + "private": "設定公開" }, "confirm": { "public": { - "title": "", - "description": "" + "title": "設定為私人面板", + "description": "確認要將此面板設為私人嗎?這將隱藏於公眾面前的面板" }, "private": { - "title": "", - "description": "" + "title": "設定為公開面板", + "description": "確認要將此面板設為公開嗎?這將使全部人皆可訪問此面板" } } }, "delete": { - "label": "", - "description": "", - "button": "", + "label": "移除此面板", + "description": "面板一旦移除就無法恢復,請謹慎操作", + "button": "移除此面板", "confirm": { - "title": "", - "description": "" + "title": "移除面板", + "description": "確認要移除此面板嗎?這將永久移除面板及其所有內容" } } } } } + }, + "error": { + "noBoard": { + "title": "歡迎來到 Homarr", + "description": "時尚、現代的儀表板,讓所有應用程式和伺服器觸手可及", + "link": "創建第一個面板", + "notice": "要讓這個頁面消失,請創建一個面板並將其設定為主面板" + }, + "notFound": { + "title": "不存在面板", + "description": "未找到指定的面板,或者是沒有訪問權限", + "link": "查看全部面板", + "notice": "如果認為鏈結應該可以訪問,請檢察鏈結或連繫管理員" + }, + "homeBoard": { + "title": "沒有主面板", + "admin": { + "description": "尚為伺服器設定主面板", + "link": "設定伺服器主面板", + "notice": "要讓這個頁面消失,請為伺服器設定主面板" + }, + "user": { + "description": "尚未設定主面板", + "link": "設定主面板", + "notice": "要讓這個頁面消失,請於偏好設定中指定主面板" + }, + "anonymous": { + "description": "伺服器管理員尚未設定主面板", + "link": "查看公開面板", + "notice": "要讓這個頁面消失,請伺服器管理員為伺服器設定一個主面板" + } + } } }, "management": { - "metaTitle": "", + "metaTitle": "管理中心", "title": { - "morning": "", - "afternoon": "", - "evening": "" + "morning": "早安,{username}", + "afternoon": "午安,{username}", + "evening": "晚安,{username}" }, "notFound": { - "title": "", - "text": "" + "title": "不存在", + "text": "找不到請求的資源" }, "navbar": { "items": { - "home": "", - "boards": "", - "apps": "", - "integrations": "", - "searchEngies": "", - "medias": "", + "home": "首頁", + "boards": "面板", + "apps": "應用程式", + "integrations": "集成", + "searchEngies": "搜尋引擎", + "medias": "多媒體", "users": { - "label": "", + "label": "使用者", "items": { - "manage": "", - "invites": "", - "groups": "" + "manage": "管理", + "invites": "邀情", + "groups": "群組" } }, "tools": { - "label": "", + "label": "工具", "items": { - "docker": "", - "logs": "", - "api": "", - "tasks": "" + "docker": "Docker", + "logs": "Logs", + "api": "API", + "certificates": "", + "tasks": "任務" } }, - "settings": "", + "settings": "設定", "help": { - "label": "", + "label": "幫助", "items": { - "documentation": "", - "submitIssue": "", - "discord": "", - "sourceCode": "" + "documentation": "說明書", + "submitIssue": "提交問題", + "discord": "Discord 社群", + "sourceCode": "源碼" } }, - "about": "" + "about": "關於" } }, "page": { "home": { "statistic": { - "board": "", - "user": "", - "invite": "", - "integration": "", - "app": "", - "group": "" + "board": "面板", + "user": "使用者", + "invite": "邀請", + "integration": "集成", + "app": "應用程式", + "group": "群組" }, "statisticLabel": { - "boards": "", - "resources": "", - "authentication": "", - "authorization": "" + "boards": "面板", + "resources": "資源", + "authentication": "認證", + "authorization": "認證" } }, "board": { - "title": "", + "title": "你的面板", "action": { "new": { - "label": "" + "label": "創建面板" }, "open": { - "label": "" + "label": "開啟面板" }, "settings": { - "label": "" + "label": "設定" }, "setHomeBoard": { + "label": "設定為首頁", + "badge": { + "label": "首頁", + "tooltip": "此面板將顯示為主面板" + } + }, + "setMobileHomeBoard": { "label": "", "badge": { "label": "", "tooltip": "" } }, + "duplicate": { + "label": "複製面板" + }, "delete": { - "label": "", + "label": "永久移除", "confirm": { - "title": "", - "description": "" + "title": "移除面板", + "description": "確認移除此面板 {name} 嗎?" } } }, "visibility": { - "public": "", - "private": "" + "public": "此面板是公開的", + "private": "此面板是私人的" }, "modal": { "createBoard": { "field": { "name": { - "label": "" + "label": "名稱" } } } } }, "media": { - "includeFromAllUsers": "" + "includeFromAllUsers": "包含來自全部使用者的多媒體" }, "user": { - "back": "", - "fieldsDisabledExternalProvider": "", + "back": "返回使用者", + "fieldsDisabledExternalProvider": "某些字段被進用,因為它們是由外部認證提供者管理的", "setting": { "general": { - "title": "", + "title": "一般", "item": { - "language": "", - "board": "", - "firstDayOfWeek": "", - "accessibility": "" + "language": "語言與地區", + "board": { + "title": "", + "type": { + "general": "", + "mobile": "" + } + }, + "defaultSearchEngine": "預設搜尋引擎", + "firstDayOfWeek": "一周的第一天", + "accessibility": "無障礙服務" } }, "security": { - "title": "" + "title": "安全" }, "board": { - "title": "" + "title": "面板" } }, "list": { - "metaTitle": "", - "title": "" + "metaTitle": "管理使用者", + "title": "使用者" }, "edit": { - "metaTitle": "" + "metaTitle": "編輯使用者 {username}" }, "create": { - "metaTitle": "", - "title": "", + "metaTitle": "創建使用者", + "title": "創建新使用者", "step": { "personalInformation": { - "label": "" + "label": "個人資料" }, "security": { - "label": "" + "label": "安全" }, "groups": { - "label": "", - "title": "", - "description": "" + "label": "群組", + "title": "選擇使用者的用戶組", + "description": "{everyoneGroup} 用戶組將分配給全部使用者,無法被移除" }, "review": { - "label": "" + "label": "預覽" }, "completed": { - "title": "" + "title": "使用者已創建" }, "error": { - "title": "" + "title": "使用者創建失敗" } }, "action": { - "createAnother": "", - "back": "" + "createAnother": "創建其他使用者", + "back": "返回使用者列表" } }, "invite": { - "title": "", + "title": "管理使用者邀請", "action": { "new": { - "title": "", - "description": "" + "title": "創建邀請", + "description": "過期後,邀請將失效,被邀請的收件人無法創建帳號" }, "copy": { - "title": "", - "description": "", - "link": "", - "button": "" + "title": "複製邀請", + "description": "邀請已生成,此模式關閉後,將無法再複製此鏈結,如果不想再邀請此人,可以隨時移除此邀請", + "link": "邀請鏈結", + "button": "複製 & 關閉" }, "delete": { - "title": "", - "description": "" + "title": "移除邀請", + "description": "確認移除此邀請嗎?,此鏈結將無法再邀請任何人" } }, "field": { "id": { - "label": "" + "label": "ID" }, "creator": { - "label": "" + "label": "創建者" }, "expirationDate": { - "label": "" + "label": "過期時間" }, "token": { - "label": "" + "label": "密鑰" } } } }, "group": { - "back": "", + "back": "返回用戶組", "setting": { "general": { - "title": "", - "owner": "", - "ownerOfGroup": "", - "ownerOfGroupDeleted": "" + "title": "一般", + "owner": "所有者", + "ownerOfGroup": "該用戶組的所有者", + "ownerOfGroupDeleted": "此用戶組的所有者已被移除,目前沒有所有者" }, "members": { - "title": "", - "search": "", - "notFound": "" + "title": "成員", + "search": "尋找成員", + "notFound": "不存在的成員" }, "permissions": { - "title": "", + "title": "權限", "form": { - "unsavedChanges": "" + "unsavedChanges": "尚有未儲存的變更" } } } }, "settings": { - "title": "", + "title": "設定", "notification": { "success": { - "message": "" + "message": "設定儲存成功" }, "error": { - "message": "" + "message": "設定儲存失敗" } }, "section": { "analytics": { - "title": "", + "title": "分析", "general": { - "title": "", - "text": "" + "title": "發送匿名分析", + "text": "Homarr 使用開源軟體 Umami 發送匿名分析,他從不收集任何個人資料,因此完全符合 GDPR 和 CCPA 要求,我們鼓勵啟用分析,因為可以幫助我們的團隊識別問題,並確認待辦事項的優先級別" }, "widgetData": { - "title": "", - "text": "" + "title": "小工具數據", + "text": "發送已設定的小工具 (及其數量),不包括網址、名稱或任何其他數據" }, "integrationData": { - "title": "", - "text": "" + "title": "集成數據", + "text": "發送已設定的集成 (及其數量),不包括網址、名稱或任何其他數據" }, "usersData": { - "title": "", - "text": "" + "title": "使用者資料", + "text": "發送使用者數量以及是否激活了 SSO" } }, "crawlingAndIndexing": { - "title": "", - "warning": "", + "title": "爬取和索引", + "warning": "啟用或禁用這裡的任何設定將嚴重影響搜尋引擎如何索引或抓取頁面,任何設定都是一個請求,是否應用這些設定取決於爬蟲,任何編輯可能需要數天或數周才能申請,某設定可能是搜尋引擎特定的", "noIndex": { - "title": "", - "text": "" + "title": "不要索引", + "text": "不要在搜尋引擎上索引網址,也不要在任何搜尋結果中顯示" }, "noFollow": { - "title": "", - "text": "" + "title": "不要追蹤", + "text": "索引不要追蹤任何鏈結,禁用此功能將導致爬蟲程式試圖跟蹤 Homarr 上的全部鏈結" }, "noTranslate": { - "title": "", - "text": "" + "title": "不要翻譯", + "text": "當網站的語言不是使用者想要閱讀的語言時,Google 將在搜尋結果中顯示一個翻譯鏈結" }, "noSiteLinksSearchBox": { - "title": "", - "text": "" + "title": "沒有網站鏈結搜索框", + "text": "Google 將與爬取的鏈結以及其他直接鏈結構建一個搜索框,啟用此功能將要求 Google 禁用該框" } }, "board": { - "title": "", + "title": "面板", "homeBoard": { - "label": "", - "description": "" + "label": "全局主面板", + "mobileLabel": "", + "description": "只有公開面板可供選擇" + } + }, + "search": { + "title": "搜尋", + "defaultSearchEngine": { + "label": "全局預設搜尋引擎", + "description": "舞法在此選擇極盛的搜尋引擎" } }, "appearance": { - "title": "", + "title": "外觀", "defaultColorScheme": { - "label": "", + "label": "預設配色方案", "options": { - "light": "", - "dark": "" + "light": "日間", + "dark": "暗黑" } } }, "culture": { - "title": "", + "title": "區域", "defaultLocale": { - "label": "" + "label": "預設語言" } } } }, "tool": { "tasks": { - "title": "", + "title": "任務", "status": { - "idle": "", - "running": "", - "error": "" + "idle": "空閒", + "running": "運行中", + "error": "錯誤" }, "job": { + "minecraftServerStatus": { + "label": "Minecraft 伺服器狀態" + }, "iconsUpdater": { - "label": "" + "label": "icon 上傳器" }, "analytics": { - "label": "" + "label": "分析" }, "smartHomeEntityState": { - "label": "" + "label": "智能居家狀態" }, "ping": { - "label": "" + "label": "Pings" }, "mediaServer": { - "label": "" + "label": "多媒體伺服器" }, "mediaOrganizer": { - "label": "" + "label": "多媒體組織者" }, "downloads": { - "label": "" + "label": "正在下載" }, "mediaRequestStats": { - "label": "" + "label": "多媒體請求狀態" }, "mediaRequestList": { - "label": "" + "label": "多媒體請求列表" }, "rssFeeds": { - "label": "" + "label": "RSS 訂閱" }, "indexerManager": { - "label": "" + "label": "索引器管理" }, "healthMonitoring": { - "label": "" + "label": "健康監測" }, "dnsHole": { - "label": "" + "label": "DNS Hole 數據" }, "sessionCleanup": { - "label": "" + "label": "會話清理" + }, + "updateChecker": { + "label": "更新檢查" + }, + "mediaTranscoding": { + "label": "多媒體轉碼中" } } }, "api": { - "title": "", + "title": "API", "modal": { "createApiToken": { - "title": "", - "description": "", - "button": "" + "title": "API 密鑰已創建", + "description": "API 密鑰已創建,請小心,此密鑰於數據庫中是加密的,永遠不再提供,如果丟失,將無法再檢索這個特定密鑰", + "button": "複製和關閉" } }, "tab": { "documentation": { - "label": "" + "label": "說明書" }, "apiKey": { - "label": "", - "title": "", + "label": "認證", + "title": "API 密鑰\n", "button": { - "createApiToken": "" + "createApiToken": "創建 API 密鑰" }, "table": { "header": { - "id": "", - "createdBy": "" + "id": "ID", + "createdBy": "創建者" } } } @@ -2186,83 +2485,641 @@ } }, "about": { - "version": "", - "text": "", + "version": "版本 {version}", + "text": "Homarr 是由社區推動的開源項目,是志願者們在維護,多虧了這些人,從 2021 年起,Homarr 一直在發展壯大,我們團隊來自許多不同的國家,完全遠程工作,於空閒時無償維護 Homarr", "accordion": { "contributors": { - "title": "", - "subtitle": "" + "title": "貢獻人員", + "subtitle": "{count} 維護代碼 & Homarr" }, "translators": { - "title": "", - "subtitle": "" + "title": "翻譯人員", + "subtitle": "{count} 翻譯了許多語言" }, "libraries": { - "title": "", - "subtitle": "" + "title": "資料庫", + "subtitle": "{count} 於 Homarr 待碼中使用" } } } } }, "docker": { - "title": "", + "title": "容器", "table": { - "updated": "", - "search": "", - "selected": "" + "updated": "已更新於 {when}", + "search": "搜尋 {count} 容器", + "selected": "{totalCount} 容器的 {selectCount}" }, "field": { "name": { - "label": "" + "label": "名稱" }, "state": { - "label": "", + "label": "狀態", "option": { - "created": "", - "running": "", - "paused": "", - "restarting": "", - "exited": "", - "removing": "", - "dead": "" + "created": "已創建", + "running": "運行中", + "paused": "已暫停", + "restarting": "正在重啟", + "exited": "已退出", + "removing": "移除中", + "dead": "廢棄" } }, "containerImage": { - "label": "" + "label": "鏡像" }, "ports": { - "label": "" + "label": "端口" } }, "action": { "start": { - "label": "", + "label": "啟動", "notification": { "success": { - "title": "", - "message": "" + "title": "容器已啟動", + "message": "容器已成功啟動" }, "error": { - "title": "", - "message": "" + "title": "容易未啟動", + "message": "容器無法啟動" } } }, "stop": { - "label": "", + "label": "停止", "notification": { "success": { - "title": "", - "message": "" + "title": "容器已停止", + "message": "容器已停止成功" }, "error": { - "title": "", - "message": "" + "title": "容器未停止", + "message": "容器無法停止" } } }, "restart": { + "label": "重啟", + "notification": { + "success": { + "title": "容器已重啟", + "message": "容器已重啟成功" + }, + "error": { + "title": "容器未重啟", + "message": "容器無法重啟" + } + } + }, + "remove": { + "label": "移除", + "notification": { + "success": { + "title": "容器已移除", + "message": "容器已移除成功" + }, + "error": { + "title": "容器未移除", + "message": "容器無法移除" + } + } + }, + "refresh": { + "label": "刷新", + "notification": { + "success": { + "title": "容器已刷新", + "message": "正在查看最新數據" + }, + "error": { + "title": "容器未刷新", + "message": "刷新容器時出現錯誤" + } + } + }, + "addToHomarr": { + "label": "新增至 Homarr", + "notification": { + "success": { + "title": "已新增至 Homarr", + "message": "已選擇的應用程式已新增至 Homarr" + }, + "error": { + "title": "無法新增至 Homarr", + "message": "已選擇的應用程式無法新增至 Homarr" + } + }, + "modal": { + "title": "新增 Docker 容器至 Homarr" + } + } + }, + "error": { + "internalServerError": "取得 Docker 容器失敗" + } + }, + "permission": { + "title": "權限", + "userSelect": { + "title": "新增使用者權限" + }, + "groupSelect": { + "title": "新增用戶組權限" + }, + "tab": { + "user": "使用者", + "group": "用戶組", + "inherited": "繼承的用戶組" + }, + "field": { + "user": { + "label": "使用者" + }, + "group": { + "label": "用戶組" + }, + "permission": { + "label": "權限" + } + }, + "action": { + "saveUser": "儲存使用者權限", + "saveGroup": "儲存用戶組權限" + } + }, + "navigationStructure": { + "manage": { + "label": "管理", + "boards": { + "label": "面板" + }, + "integrations": { + "label": "集成", + "edit": { + "label": "編輯" + }, + "new": { + "label": "創建" + } + }, + "search-engines": { + "label": "搜尋引擎", + "new": { + "label": "創建" + }, + "edit": { + "label": "編輯" + } + }, + "medias": { + "label": "多媒體" + }, + "apps": { + "label": "應用程式", + "new": { + "label": "創建" + }, + "edit": { + "label": "編輯" + } + }, + "users": { + "label": "使用者", + "create": { + "label": "創建" + }, + "general": "一般", + "security": "安全", + "board": "面板", + "groups": { + "label": "用戶組" + }, + "invites": { + "label": "邀請" + } + }, + "tools": { + "label": "工具", + "docker": { + "label": "Docker" + }, + "logs": { + "label": "Logs" + }, + "certificates": { + "label": "" + } + }, + "settings": { + "label": "設定" + }, + "about": { + "label": "關於" + } + } + }, + "search": { + "placeholder": "搜尋任意內容", + "nothingFound": "不存在", + "error": { + "fetch": "取得數據時發生錯誤" + }, + "mode": { + "appIntegrationBoard": { + "help": "搜尋應用程式,集成或面板", + "group": { + "app": { + "title": "應用程式", + "children": { + "action": { + "open": { + "label": "開啟應用程式網址" + }, + "edit": { + "label": "編輯應用程式" + } + }, + "detail": { + "title": "為應用程式選擇一個動作" + } + } + }, + "board": { + "title": "面板", + "children": { + "action": { + "open": { + "label": "開啟面板" + }, + "homeBoard": { + "label": "設定為主面板" + }, + "mobileBoard": { + "label": "" + }, + "settings": { + "label": "開啟設定" + } + }, + "detail": { + "title": "為面板選擇一個動作" + } + } + }, + "integration": { + "title": "集成" + } + } + }, + "command": { + "help": "啟用命令模式", + "group": { + "localCommand": { + "title": "本地命令" + }, + "globalCommand": { + "title": "全局命令", + "option": { + "colorScheme": { + "light": "切換日間模式", + "dark": "切換暗黑模式" + }, + "language": { + "label": "編輯語言", + "children": { + "detail": { + "title": "選擇主要語言" + } + } + }, + "newBoard": { + "label": "創建新面板" + }, + "importBoard": { + "label": "匯入面板" + }, + "newApp": { + "label": "創建新應用程式" + }, + "newIntegration": { + "label": "創建新集成", + "children": { + "detail": { + "title": "選擇創建集成的類別" + } + } + }, + "newUser": { + "label": "創建新使用者" + }, + "newInvite": { + "label": "創建新邀請" + }, + "newGroup": { + "label": "創建新用戶組" + } + } + } + } + }, + "media": { + "requestMovie": "請求電影", + "requestSeries": "請求系列", + "openIn": "開啟於 {kind}" + }, + "external": { + "help": "使用外部搜尋引擎", + "group": { + "searchEngine": { + "title": "搜尋引擎", + "children": { + "action": { + "search": { + "label": "使用 {name} 搜尋" + } + }, + "detail": { + "title": "為搜尋引擎選擇一個動作" + }, + "searchResults": { + "title": "選擇搜尋結果進行操作" + } + }, + "option": { + "google": { + "name": "Google", + "description": "使用 Google 搜尋網路" + }, + "bing": { + "name": "Bing", + "description": "使用 Bing 搜尋網路" + }, + "duckduckgo": { + "name": "DuckDuckGo", + "description": "使用 DuckDuckGo 搜尋網路" + }, + "torrent": { + "name": "種子", + "description": "於 torrentdownloads.pro 上搜尋種子" + }, + "youTube": { + "name": "YouTube", + "description": "使用 YouTube 搜尋影音" + } + } + } + } + }, + "help": { + "group": { + "mode": { + "title": "模式" + }, + "help": { + "title": "幫助", + "option": { + "documentation": { + "label": "說明書" + }, + "submitIssue": { + "label": "提交問題" + }, + "discord": { + "label": "Discord 社群" + } + } + } + } + }, + "home": { + "group": { + "search": { + "title": "搜尋", + "option": { + "other": { + "label": "使用其他搜尋引擎進行搜尋" + }, + "no-default": { + "label": "無預設搜尋引擎", + "description": "於偏好設定中設定預設搜尋引擎" + }, + "search": { + "label": "使用 {name} 搜尋 {query}" + }, + "from-integration": { + "description": "開始輸入以進行搜尋" + } + } + }, + "local": { + "title": "本地結果" + } + } + }, + "page": { + "help": "搜尋頁面", + "group": { + "page": { + "title": "頁面", + "option": { + "manageHome": { + "label": "管理首頁" + }, + "manageBoard": { + "label": "管理面板" + }, + "manageApp": { + "label": "管理應用程式" + }, + "manageIntegration": { + "label": "管理集成" + }, + "manageSearchEngine": { + "label": "管理搜尋引擎" + }, + "manageMedia": { + "label": "管理多媒體" + }, + "manageUser": { + "label": "管理使用者" + }, + "manageInvite": { + "label": "管理邀請" + }, + "manageGroup": { + "label": "管理用戶組" + }, + "manageDocker": { + "label": "管理 Docker" + }, + "manageApi": { + "label": "Swagger API" + }, + "manageLog": { + "label": "查看 Logs" + }, + "manageTask": { + "label": "管理任務" + }, + "manageSettings": { + "label": "全局設定" + }, + "about": { + "label": "關於" + }, + "homeBoard": { + "label": "主面板" + }, + "preferences": { + "label": "偏好設定" + } + } + } + } + }, + "userGroup": { + "help": "搜尋使用者或用戶組", + "group": { + "user": { + "title": "使用者", + "children": { + "action": { + "detail": { + "label": "顯示使用者詳情" + } + }, + "detail": { + "title": "為使用者選擇一個動作" + } + } + }, + "group": { + "title": "用戶組", + "children": { + "action": { + "detail": { + "label": "顯示用戶組詳情" + }, + "manageMember": { + "label": "管理成員" + }, + "managePermission": { + "label": "管理權限" + } + }, + "detail": { + "title": "為用戶組選擇一個動作" + } + } + } + } + } + }, + "engine": { + "search": "尋找搜尋引擎", + "field": { + "name": { + "label": "名稱" + }, + "short": { + "label": "不足" + }, + "urlTemplate": { + "label": "網址搜尋面板" + }, + "description": { + "label": "描述" + } + }, + "page": { + "list": { + "title": "搜尋引擎", + "noResults": { + "title": "尚未設定搜尋引擎", + "action": "創建搜尋引情" + }, + "interactive": "交互,使用集成" + }, + "create": { + "title": "創建搜尋引擎", + "notification": { + "success": { + "title": "搜尋引擎已創建", + "message": "搜尋引擎已創建成功" + }, + "error": { + "title": "搜尋引擎未創建", + "message": "搜尋引擎無法創建" + } + } + }, + "edit": { + "title": "編輯搜尋引擎", + "notification": { + "success": { + "title": "應用編輯成功", + "message": "搜尋引擎已儲存成功" + }, + "error": { + "title": "無法應用變更", + "message": "搜尋引擎無法儲存" + } + }, + "configControl": "設定", + "searchEngineType": { + "generic": "一般", + "fromIntegration": "來自集成" + } + }, + "delete": { + "title": "移除搜尋引擎", + "message": "確認要移除此搜尋引擎 {name} 嗎?", + "notification": { + "success": { + "title": "搜尋引擎已移除", + "message": "搜尋引擎已移除成功" + }, + "error": { + "title": "搜尋引擎未移除", + "message": "搜尋引擎無法移除" + } + } + } + }, + "media": { + "request": { + "modal": { + "title": "請求 {name}", + "table": { + "header": { + "season": "季", + "episodes": "劇集" + } + }, + "button": { + "send": "發送請求" + } + } + } + } + } + }, + "certificate": { + "page": { + "list": { + "title": "", + "description": "", + "noResults": { + "title": "" + }, + "expires": "" + } + }, + "action": { + "create": { "label": "", "notification": { "success": { @@ -2277,6 +3134,7 @@ }, "remove": { "label": "", + "confirm": "", "notification": { "success": { "title": "", @@ -2287,460 +3145,6 @@ "message": "" } } - }, - "refresh": { - "label": "", - "notification": { - "success": { - "title": "", - "message": "" - }, - "error": { - "title": "", - "message": "" - } - } - } - } - }, - "permission": { - "title": "", - "userSelect": { - "title": "" - }, - "groupSelect": { - "title": "" - }, - "tab": { - "user": "", - "group": "", - "inherited": "" - }, - "field": { - "user": { - "label": "" - }, - "group": { - "label": "" - }, - "permission": { - "label": "" - } - }, - "action": { - "saveUser": "", - "saveGroup": "" - } - }, - "navigationStructure": { - "manage": { - "label": "", - "boards": { - "label": "" - }, - "integrations": { - "label": "", - "edit": { - "label": "" - }, - "new": { - "label": "" - } - }, - "search-engines": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "" - } - }, - "medias": { - "label": "" - }, - "apps": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "" - } - }, - "users": { - "label": "", - "create": { - "label": "" - }, - "general": "", - "security": "", - "board": "", - "groups": { - "label": "" - }, - "invites": { - "label": "" - } - }, - "tools": { - "label": "", - "docker": { - "label": "" - }, - "logs": { - "label": "" - } - }, - "settings": { - "label": "" - }, - "about": { - "label": "" - } - } - }, - "search": { - "placeholder": "", - "nothingFound": "", - "error": { - "fetch": "" - }, - "mode": { - "appIntegrationBoard": { - "help": "", - "group": { - "app": { - "title": "", - "children": { - "action": { - "open": { - "label": "" - }, - "edit": { - "label": "" - } - }, - "detail": { - "title": "" - } - } - }, - "board": { - "title": "", - "children": { - "action": { - "open": { - "label": "" - }, - "homeBoard": { - "label": "" - }, - "settings": { - "label": "" - } - }, - "detail": { - "title": "" - } - } - }, - "integration": { - "title": "" - } - } - }, - "command": { - "help": "", - "group": { - "localCommand": { - "title": "" - }, - "globalCommand": { - "title": "", - "option": { - "colorScheme": { - "light": "", - "dark": "" - }, - "language": { - "label": "", - "children": { - "detail": { - "title": "" - } - } - }, - "newBoard": { - "label": "" - }, - "importBoard": { - "label": "" - }, - "newApp": { - "label": "" - }, - "newIntegration": { - "label": "", - "children": { - "detail": { - "title": "" - } - } - }, - "newUser": { - "label": "" - }, - "newInvite": { - "label": "" - }, - "newGroup": { - "label": "" - } - } - } - } - }, - "external": { - "help": "", - "group": { - "searchEngine": { - "title": "", - "children": { - "action": { - "search": { - "label": "" - } - }, - "detail": { - "title": "" - }, - "searchResults": { - "title": "" - } - }, - "option": { - "google": { - "name": "", - "description": "" - }, - "bing": { - "name": "", - "description": "" - }, - "duckduckgo": { - "name": "", - "description": "" - }, - "torrent": { - "name": "", - "description": "" - }, - "youTube": { - "name": "", - "description": "" - } - } - } - } - }, - "help": { - "group": { - "mode": { - "title": "" - }, - "help": { - "title": "", - "option": { - "documentation": { - "label": "" - }, - "submitIssue": { - "label": "" - }, - "discord": { - "label": "" - } - } - } - } - }, - "home": { - "group": { - "local": { - "title": "" - } - } - }, - "page": { - "help": "", - "group": { - "page": { - "title": "", - "option": { - "manageHome": { - "label": "" - }, - "manageBoard": { - "label": "" - }, - "manageApp": { - "label": "" - }, - "manageIntegration": { - "label": "" - }, - "manageSearchEngine": { - "label": "" - }, - "manageMedia": { - "label": "" - }, - "manageUser": { - "label": "" - }, - "manageInvite": { - "label": "" - }, - "manageGroup": { - "label": "" - }, - "manageDocker": { - "label": "" - }, - "manageApi": { - "label": "" - }, - "manageLog": { - "label": "" - }, - "manageTask": { - "label": "" - }, - "manageSettings": { - "label": "" - }, - "about": { - "label": "" - }, - "homeBoard": { - "label": "" - }, - "preferences": { - "label": "" - } - } - } - } - }, - "userGroup": { - "help": "", - "group": { - "user": { - "title": "", - "children": { - "action": { - "detail": { - "label": "" - } - }, - "detail": { - "title": "" - } - } - }, - "group": { - "title": "", - "children": { - "action": { - "detail": { - "label": "" - }, - "manageMember": { - "label": "" - }, - "managePermission": { - "label": "" - } - }, - "detail": { - "title": "" - } - } - } - } - } - }, - "engine": { - "search": "", - "field": { - "name": { - "label": "" - }, - "short": { - "label": "" - }, - "urlTemplate": { - "label": "" - }, - "description": { - "label": "" - } - }, - "page": { - "list": { - "title": "", - "noResults": { - "title": "", - "action": "" - }, - "interactive": "" - }, - "create": { - "title": "", - "notification": { - "success": { - "title": "", - "message": "" - }, - "error": { - "title": "", - "message": "" - } - } - }, - "edit": { - "title": "", - "notification": { - "success": { - "title": "", - "message": "" - }, - "error": { - "title": "", - "message": "" - } - }, - "configControl": "", - "searchEngineType": { - "generic": "", - "fromIntegration": "" - } - }, - "delete": { - "title": "", - "message": "", - "notification": { - "success": { - "title": "", - "message": "" - }, - "error": { - "title": "", - "message": "" - } - } - } } } } diff --git a/packages/ui/package.json b/packages/ui/package.json index 80889e4ce..568d4b18e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -29,20 +29,21 @@ "@homarr/log": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.15.1", - "@mantine/dates": "^7.15.1", - "@mantine/hooks": "^7.15.1", - "@tabler/icons-react": "^3.24.0", - "mantine-react-table": "2.0.0-beta.7", - "next": "^14.2.20", - "react": "^19.0.0" + "@mantine/core": "^7.16.0", + "@mantine/dates": "^7.16.0", + "@mantine/hooks": "^7.16.0", + "@tabler/icons-react": "^3.28.1", + "mantine-react-table": "2.0.0-beta.8", + "next": "15.1.4", + "react": "19.0.0", + "react-dom": "19.0.0" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/css-modules": "^1.0.5", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/ui/src/components/select-with-custom-items.tsx b/packages/ui/src/components/select-with-custom-items.tsx index 410fe3429..bbed3cd1f 100644 --- a/packages/ui/src/components/select-with-custom-items.tsx +++ b/packages/ui/src/components/select-with-custom-items.tsx @@ -17,6 +17,7 @@ export interface SelectWithCustomItemsProps withAsterisk?: boolean; onBlur?: (event: React.FocusEvent) => void; onFocus?: (event: React.FocusEvent) => void; + w?: string; } type Props = SelectWithCustomItemsProps & { @@ -30,6 +31,7 @@ export const SelectWithCustomItems = ({ defaultValue, placeholder, SelectOption, + w, ...props }: Props) => { const combobox = useCombobox({ @@ -75,6 +77,7 @@ export const SelectWithCustomItems = ({ onClick={toggle} rightSectionPointerEvents="none" multiline + w={w} > {selectedOption ? : {placeholder}} diff --git a/packages/validation/package.json b/packages/validation/package.json index 4f2bba2d0..a26e0c598 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -24,16 +24,15 @@ "prettier": "@homarr/prettier-config", "dependencies": { "@homarr/definitions": "workspace:^0.1.0", - "@homarr/old-schema": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0", "zod": "^3.24.1", - "zod-form-data": "^2.0.2" + "zod-form-data": "^2.0.5" }, "devDependencies": { "@homarr/eslint-config": "workspace:^0.2.0", "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/validation/src/app.ts b/packages/validation/src/app.ts index 6ac45ac35..dfe1a749a 100644 --- a/packages/validation/src/app.ts +++ b/packages/validation/src/app.ts @@ -4,12 +4,19 @@ const manageAppSchema = z.object({ name: z.string().min(1).max(64), description: z.string().max(512).nullable(), iconUrl: z.string().min(1), - href: z.string().nullable(), + href: z + .string() + .url() + .regex(/^https?:\/\//) // Only allow http and https for security reasons (javascript: is not allowed) + .nullable(), }); const editAppSchema = manageAppSchema.and(z.object({ id: z.string() })); export const appSchemas = { manage: manageAppSchema, + createMany: z + .array(manageAppSchema.omit({ iconUrl: true }).and(z.object({ iconUrl: z.string().min(1).nullable() }))) + .min(1), edit: editAppSchema, }; diff --git a/packages/validation/src/board.ts b/packages/validation/src/board.ts index 33930063c..1fd121a95 100644 --- a/packages/validation/src/board.ts +++ b/packages/validation/src/board.ts @@ -1,5 +1,4 @@ import { z } from "zod"; -import { zfd } from "zod-form-data"; import { backgroundImageAttachments, @@ -9,7 +8,6 @@ import { } from "@homarr/definitions"; import { zodEnumFromArray } from "./enums"; -import { createCustomErrorParams } from "./form/i18n"; import { createSavePermissionsSchema } from "./permissions"; import { commonItemSchema, createSectionSchema } from "./shared"; @@ -30,6 +28,11 @@ const renameSchema = z.object({ name: boardNameSchema, }); +const duplicateSchema = z.object({ + id: z.string(), + name: boardNameSchema, +}); + const changeVisibilitySchema = z.object({ id: z.string(), visibility: z.enum(["public", "private"]), @@ -69,53 +72,6 @@ const permissionsSchema = z.object({ id: z.string(), }); -export const oldmarrImportConfigurationSchema = z.object({ - name: boardNameSchema, - onlyImportApps: z.boolean().default(false), - distinctAppsByHref: z.boolean().default(true), - screenSize: z.enum(["lg", "md", "sm"]).default("lg"), - sidebarBehaviour: z.enum(["remove-items", "last-section"]).default("last-section"), -}); - -export type OldmarrImportConfiguration = z.infer; - -export const superRefineJsonImportFile = (value: File | null, context: z.RefinementCtx) => { - if (!value) { - return context.addIssue({ - code: "invalid_type", - expected: "object", - received: "null", - }); - } - - if (value.type !== "application/json") { - return context.addIssue({ - code: "custom", - params: createCustomErrorParams({ - key: "invalidFileType", - params: { expected: "JSON" }, - }), - }); - } - - if (value.size > 1024 * 1024) { - return context.addIssue({ - code: "custom", - params: createCustomErrorParams({ - key: "fileTooLarge", - params: { maxSize: "1 MB" }, - }), - }); - } - - return null; -}; - -const importJsonFileSchema = zfd.formData({ - file: zfd.file().superRefine(superRefineJsonImportFile), - configuration: zfd.json(oldmarrImportConfigurationSchema), -}); - const savePermissionsSchema = createSavePermissionsSchema(zodEnumFromArray(boardPermissions)); z.object({ @@ -129,13 +85,14 @@ z.object({ }); export const boardSchemas = { + name: boardNameSchema, byName: byNameSchema, savePartialSettings: savePartialSettingsSchema, save: saveSchema, create: createSchema, + duplicate: duplicateSchema, rename: renameSchema, changeVisibility: changeVisibilitySchema, permissions: permissionsSchema, savePermissions: savePermissionsSchema, - importOldmarrConfig: importJsonFileSchema, }; diff --git a/packages/validation/src/certificates.ts b/packages/validation/src/certificates.ts new file mode 100644 index 000000000..7ad6d3aeb --- /dev/null +++ b/packages/validation/src/certificates.ts @@ -0,0 +1,52 @@ +import { z } from "zod"; + +import { createCustomErrorParams } from "./form/i18n"; + +const validFileNameSchema = z.string().regex(/^[\w\-. ]+$/); + +export const superRefineCertificateFile = (value: File | null, context: z.RefinementCtx) => { + if (!value) { + return context.addIssue({ + code: "invalid_type", + expected: "object", + received: "null", + }); + } + + const result = validFileNameSchema.safeParse(value.name); + if (!result.success) { + return context.addIssue({ + code: "custom", + params: createCustomErrorParams({ + key: "invalidFileName", + params: {}, + }), + }); + } + + if (value.type !== "application/x-x509-ca-cert" && value.type !== "application/pkix-cert") { + return context.addIssue({ + code: "custom", + params: createCustomErrorParams({ + key: "invalidFileType", + params: { expected: ".crt" }, + }), + }); + } + + if (value.size > 1024 * 1024) { + return context.addIssue({ + code: "custom", + params: createCustomErrorParams({ + key: "fileTooLarge", + params: { maxSize: "1 MB" }, + }), + }); + } + + return null; +}; + +export const certificateSchemas = { + validFileNameSchema, +}; diff --git a/packages/validation/src/common.ts b/packages/validation/src/common.ts index 68506df63..3decf20be 100644 --- a/packages/validation/src/common.ts +++ b/packages/validation/src/common.ts @@ -15,8 +15,21 @@ const searchSchema = z.object({ limit: z.number().int().positive().default(10), }); +const mediaRequestOptionsSchema = z.object({ + mediaId: z.number(), + mediaType: z.enum(["tv", "movie"]), +}); + +const requestMediaSchema = z.object({ + mediaType: z.enum(["tv", "movie"]), + mediaId: z.number(), + seasons: z.array(z.number().min(0)).optional(), +}); + export const commonSchemas = { paginated: paginatedSchema, byId: byIdSchema, search: searchSchema, + mediaRequestOptions: mediaRequestOptionsSchema, + requestMedia: requestMediaSchema, }; diff --git a/packages/validation/src/index.ts b/packages/validation/src/index.ts index dd218ff7c..955031786 100644 --- a/packages/validation/src/index.ts +++ b/packages/validation/src/index.ts @@ -1,5 +1,6 @@ import { appSchemas } from "./app"; import { boardSchemas } from "./board"; +import { certificateSchemas } from "./certificates"; import { commonSchemas } from "./common"; import { groupSchemas } from "./group"; import { iconsSchemas } from "./icons"; @@ -7,6 +8,7 @@ import { integrationSchemas } from "./integration"; import { locationSchemas } from "./location"; import { mediaSchemas } from "./media"; import { searchEngineSchemas } from "./search-engine"; +import { settingsSchemas } from "./settings"; import { userSchemas } from "./user"; import { widgetSchemas } from "./widgets"; @@ -21,11 +23,11 @@ export const validation = { icons: iconsSchemas, searchEngine: searchEngineSchemas, media: mediaSchemas, + settings: settingsSchemas, common: commonSchemas, + certificates: certificateSchemas, }; -export { oldmarrImportConfigurationSchema, superRefineJsonImportFile } from "./board"; -export type { OldmarrImportConfiguration } from "./board"; export { createSectionSchema, itemAdvancedOptionsSchema, @@ -33,5 +35,7 @@ export { type BoardItemAdvancedOptions, type BoardItemIntegration, } from "./shared"; +export { superRefineCertificateFile } from "./certificates"; export { passwordRequirements } from "./user"; export { supportedMediaUploadFormats } from "./media"; +export { zodEnumFromArray, zodUnionFromArray } from "./enums"; diff --git a/packages/validation/src/integration.ts b/packages/validation/src/integration.ts index 1a7529087..e9606a268 100644 --- a/packages/validation/src/integration.ts +++ b/packages/validation/src/integration.ts @@ -7,7 +7,10 @@ import { createSavePermissionsSchema } from "./permissions"; const integrationCreateSchema = z.object({ name: z.string().nonempty().max(127), - url: z.string().url(), + url: z + .string() + .url() + .regex(/^https?:\/\//), // Only allow http and https for security reasons (javascript: is not allowed) kind: zodEnumFromArray(integrationKinds), secrets: z.array( z.object({ @@ -15,6 +18,7 @@ const integrationCreateSchema = z.object({ value: z.string().nonempty(), }), ), + attemptSearchEngineCreation: z.boolean(), }); const integrationUpdateSchema = z.object({ diff --git a/packages/validation/src/search-engine.ts b/packages/validation/src/search-engine.ts index dbf9b0f4b..720f5fb86 100644 --- a/packages/validation/src/search-engine.ts +++ b/packages/validation/src/search-engine.ts @@ -5,7 +5,7 @@ import type { SearchEngineType } from "@homarr/definitions"; const genericSearchEngine = z.object({ type: z.literal("generic" satisfies SearchEngineType), - urlTemplate: z.string().min(1).startsWith("http").includes("%s"), + urlTemplate: z.string().min(1).startsWith("http").includes("%s"), // Only allow http and https for security reasons (javascript: is not allowed) }); const fromIntegrationSearchEngine = z.object({ diff --git a/packages/validation/src/settings.ts b/packages/validation/src/settings.ts new file mode 100644 index 000000000..8eb5225ac --- /dev/null +++ b/packages/validation/src/settings.ts @@ -0,0 +1,20 @@ +import { z } from "zod"; + +const initSettingsSchema = z.object({ + analytics: z.object({ + enableGeneral: z.boolean(), + enableWidgetData: z.boolean(), + enableIntegrationData: z.boolean(), + enableUserData: z.boolean(), + }), + crawlingAndIndexing: z.object({ + noIndex: z.boolean(), + noFollow: z.boolean(), + noTranslate: z.boolean(), + noSiteLinksSearchBox: z.boolean(), + }), +}); + +export const settingsSchemas = { + init: initSettingsSchema, +}; diff --git a/packages/validation/src/user.ts b/packages/validation/src/user.ts index f06fb67ec..c97ff5054 100644 --- a/packages/validation/src/user.ts +++ b/packages/validation/src/user.ts @@ -106,7 +106,12 @@ const changePasswordSchema = addConfirmPasswordRefinement(baseChangePasswordSche const changePasswordApiSchema = addConfirmPasswordRefinement(baseChangePasswordSchema); const changeHomeBoardSchema = z.object({ - homeBoardId: z.string().min(1), + homeBoardId: z.string().nullable(), + mobileHomeBoardId: z.string().nullable(), +}); + +const changeDefaultSearchEngineSchema = z.object({ + defaultSearchEngineId: z.string().min(1), }); const changeColorSchemeSchema = z.object({ @@ -131,7 +136,8 @@ export const userSchemas = { password: passwordSchema, editProfile: editProfileSchema, changePassword: changePasswordSchema, - changeHomeBoard: changeHomeBoardSchema, + changeHomeBoards: changeHomeBoardSchema, + changeDefaultSearchEngine: changeDefaultSearchEngineSchema, changePasswordApi: changePasswordApiSchema, changeColorScheme: changeColorSchemeSchema, firstDayOfWeek: firstDayOfWeekSchema, diff --git a/packages/widgets/package.json b/packages/widgets/package.json index d13a3a178..cb493a6a3 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -41,29 +41,30 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", - "@mantine/core": "^7.15.1", - "@mantine/hooks": "^7.15.1", - "@tabler/icons-react": "^3.24.0", - "@tiptap/extension-color": "2.10.3", - "@tiptap/extension-highlight": "2.10.3", - "@tiptap/extension-image": "2.10.3", - "@tiptap/extension-link": "^2.10.3", - "@tiptap/extension-table": "2.10.3", - "@tiptap/extension-table-cell": "2.10.3", - "@tiptap/extension-table-header": "2.10.3", - "@tiptap/extension-table-row": "2.10.3", - "@tiptap/extension-task-item": "2.10.3", - "@tiptap/extension-task-list": "2.10.3", - "@tiptap/extension-text-align": "2.10.3", - "@tiptap/extension-text-style": "2.10.3", - "@tiptap/extension-underline": "2.10.3", - "@tiptap/react": "^2.10.3", - "@tiptap/starter-kit": "^2.10.3", + "@mantine/core": "^7.16.0", + "@mantine/hooks": "^7.16.0", + "@tabler/icons-react": "^3.28.1", + "@tiptap/extension-color": "2.11.2", + "@tiptap/extension-highlight": "2.11.2", + "@tiptap/extension-image": "2.11.2", + "@tiptap/extension-link": "^2.11.2", + "@tiptap/extension-table": "2.11.2", + "@tiptap/extension-table-cell": "2.11.2", + "@tiptap/extension-table-header": "2.11.2", + "@tiptap/extension-table-row": "2.11.2", + "@tiptap/extension-task-item": "2.11.2", + "@tiptap/extension-task-list": "2.11.2", + "@tiptap/extension-text-align": "2.11.2", + "@tiptap/extension-text-style": "2.11.2", + "@tiptap/extension-underline": "2.11.2", + "@tiptap/react": "^2.11.2", + "@tiptap/starter-kit": "^2.11.2", "clsx": "^2.1.1", "dayjs": "^1.11.13", - "mantine-react-table": "2.0.0-beta.7", - "next": "^14.2.20", - "react": "^19.0.0", + "mantine-react-table": "2.0.0-beta.8", + "next": "15.1.4", + "react": "19.0.0", + "react-dom": "19.0.0", "video.js": "^8.21.0" }, "devDependencies": { @@ -71,7 +72,7 @@ "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", "@types/video.js": "^7.3.58", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/packages/widgets/src/app/component.tsx b/packages/widgets/src/app/component.tsx index 989de06c3..77039a7af 100644 --- a/packages/widgets/src/app/component.tsx +++ b/packages/widgets/src/app/component.tsx @@ -7,7 +7,6 @@ import { IconLoader } from "@tabler/icons-react"; import combineClasses from "clsx"; import { clientApi } from "@homarr/api/client"; -import { parseAppHrefWithVariablesClient } from "@homarr/common/client"; import { useRegisterSpotlightContextResults } from "@homarr/spotlight"; import { useI18n } from "@homarr/translation/client"; @@ -31,26 +30,30 @@ export default function AppWidget({ options, isEditMode }: WidgetComponentProps< ); useRegisterSpotlightContextResults( `app-${app.id}`, - [ - { - id: app.id, - name: app.name, - icon: app.iconUrl, - interaction() { - return { - type: "link", - href: parseAppHrefWithVariablesClient(app.href ?? ""), - newTab: options.openInNewTab, - }; - }, - }, - ], + app.href + ? [ + { + id: app.id, + name: app.name, + icon: app.iconUrl, + interaction() { + return { + type: "link", + // We checked above that app.href is defined + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + href: app.href!, + newTab: options.openInNewTab, + }; + }, + }, + ] + : [], [app, options.openInNewTab], ); return ( @@ -88,14 +91,21 @@ export default function AppWidget({ options, isEditMode }: WidgetComponentProps< } interface AppLinkProps { - href: string; + href: string | undefined; openInNewTab: boolean; enabled: boolean; } const AppLink = ({ href, openInNewTab, enabled, children }: PropsWithChildren) => enabled ? ( - + {children} ) : ( diff --git a/packages/widgets/src/app/ping/ping-indicator.tsx b/packages/widgets/src/app/ping/ping-indicator.tsx index 1bf781427..b96841376 100644 --- a/packages/widgets/src/app/ping/ping-indicator.tsx +++ b/packages/widgets/src/app/ping/ping-indicator.tsx @@ -3,7 +3,6 @@ import { IconCheck, IconX } from "@tabler/icons-react"; import type { RouterOutputs } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; -import { parseAppHrefWithVariablesClient } from "@homarr/common/client"; import { PingDot } from "./ping-dot"; @@ -14,7 +13,7 @@ interface PingIndicatorProps { export const PingIndicator = ({ href }: PingIndicatorProps) => { const [ping] = clientApi.widget.app.ping.useSuspenseQuery( { - url: parseAppHrefWithVariablesClient(href), + url: href, }, { refetchOnMount: false, @@ -25,7 +24,7 @@ export const PingIndicator = ({ href }: PingIndicatorProps) => { const [pingResult, setPingResult] = useState(ping); clientApi.widget.app.updatedPing.useSubscription( - { url: parseAppHrefWithVariablesClient(href) }, + { url: href }, { onData(data) { setPingResult(data); diff --git a/packages/widgets/src/bookmarks/component.tsx b/packages/widgets/src/bookmarks/component.tsx index cfc874661..b4383fb42 100644 --- a/packages/widgets/src/bookmarks/component.tsx +++ b/packages/widgets/src/bookmarks/component.tsx @@ -4,7 +4,6 @@ import { Anchor, Box, Card, Divider, Flex, Group, Stack, Text, Title, UnstyledBu import type { RouterOutputs } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; -import { parseAppHrefWithVariablesClient } from "@homarr/common/client"; import { useRegisterSpotlightContextResults } from "@homarr/spotlight"; import type { WidgetComponentProps } from "../definition"; @@ -19,18 +18,22 @@ export default function BookmarksWidget({ options, width, height, itemId }: Widg useRegisterSpotlightContextResults( `bookmark-${itemId}`, - data.map((app) => ({ - id: app.id, - name: app.name, - icon: app.iconUrl, - interaction() { - return { - type: "link", - href: parseAppHrefWithVariablesClient(app.href ?? ""), - newTab: false, - }; - }, - })), + data + .filter((app) => app.href !== null) + .map((app) => ({ + id: app.id, + name: app.name, + icon: app.iconUrl, + interaction() { + return { + type: "link", + // We checked above that app.href is defined + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + href: app.href!, + newTab: false, + }; + }, + })), [data], ); diff --git a/packages/widgets/src/dns-hole/controls/component.tsx b/packages/widgets/src/dns-hole/controls/component.tsx index 36324d329..5c98e5e6a 100644 --- a/packages/widgets/src/dns-hole/controls/component.tsx +++ b/packages/widgets/src/dns-hole/controls/component.tsx @@ -29,7 +29,6 @@ import { useI18n } from "@homarr/translation/client"; import type { widgetKind } from "."; import type { WidgetComponentProps } from "../../definition"; -import { NoIntegrationSelectedError } from "../../errors"; import TimerModal from "./TimerModal"; const dnsLightStatus = (enabled: boolean | undefined) => @@ -184,10 +183,6 @@ export default function DnsHoleControlsWidget({ const controlAllButtonsVisible = options.showToggleAllButtons && integrationsWithInteractions.length > 0; - if (integrationIds.length === 0) { - throw new NoIntegrationSelectedError(); - } - return ( ) { const [summaries] = clientApi.widget.dnsHole.summary.useSuspenseQuery( @@ -62,10 +61,6 @@ export default function DnsHoleSummaryWidget({ options, integrationIds }: Widget const data = useMemo(() => summaries.flatMap(({ summary }) => summary), [summaries]); - if (integrationIds.length === 0) { - throw new NoIntegrationSelectedError(); - } - return ( {data.length > 0 ? ( @@ -103,11 +98,11 @@ const stats = [ }, { icon: IconPercentage, - value: (data) => - `${formatNumber( - data.reduce((count, { adsBlockedTodayPercentage }) => count + adsBlockedTodayPercentage, 0), - 2, - )}%`, + value: (data) => { + const totalCount = data.reduce((count, { dnsQueriesToday }) => count + dnsQueriesToday, 0); + const blocked = data.reduce((count, { adsBlockedToday }) => count + adsBlockedToday, 0); + return `${formatNumber(totalCount === 0 ? 0 : (blocked / totalCount) * 100, 2)}%`; + }, label: (t) => t("widget.dnsHoleSummary.data.adsBlockedTodayPercentage"), color: "rgba(255, 165, 20, 0.4)", // YELLOW }, @@ -123,11 +118,17 @@ const stats = [ }, { icon: IconWorldWww, - value: (data) => - formatNumber( - data.reduce((count, { domainsBeingBlocked }) => count + domainsBeingBlocked, 0), - 2, - ), + value: (data) => { + // We use a suffix to indicate that there might be more domains in the at least two lists. + const suffix = data.length >= 2 ? "+" : ""; + return ( + formatNumber( + data.reduce((count, { domainsBeingBlocked }) => count + domainsBeingBlocked, 0), + 2, + ) + suffix + ); + }, + tooltip: (data, t) => (data.length >= 2 ? t("widget.dnsHoleSummary.domainsTooltip") : undefined), label: (t) => t("widget.dnsHoleSummary.data.domainsBeingBlocked"), color: "rgba(0, 176, 96, 0.4)", // GREEN }, @@ -135,7 +136,8 @@ const stats = [ interface StatItem { icon: TablerIcon; - value: (x: DnsHoleSummary[]) => string; + value: (summaries: DnsHoleSummary[]) => string; + tooltip?: (summaries: DnsHoleSummary[], t: TranslationFunction) => string | undefined; label: stringOrTranslation; color: string; } @@ -149,58 +151,61 @@ interface StatCardProps { const StatCard = ({ item, data, usePiHoleColors, t }: StatCardProps) => { const { ref, height, width } = useElementSize(); const isLong = width > height + 20; + const tooltip = item.tooltip?.(data, t); return ( - - + - - + - {item.value(data)} - - {item.label && ( - - {translateIfNecessary(t, item.label)} + + {item.value(data)} - )} + {item.label && ( + + {translateIfNecessary(t, item.label)} + + )} + - - + + ); }; diff --git a/packages/widgets/src/downloads/component.tsx b/packages/widgets/src/downloads/component.tsx index 37aac837c..39da51449 100644 --- a/packages/widgets/src/downloads/component.tsx +++ b/packages/widgets/src/downloads/component.tsx @@ -10,10 +10,12 @@ import { AvatarGroup, Button, Center, + Chip, Divider, Group, Modal, Paper, + Popover, Progress, Space, Stack, @@ -26,6 +28,7 @@ import type { IconProps } from "@tabler/icons-react"; import { IconAlertTriangle, IconCirclesRelation, + IconFilter, IconInfinity, IconInfoCircle, IconPlayerPause, @@ -45,7 +48,11 @@ import type { ExtendedClientStatus, ExtendedDownloadClientItem } from "@homarr/i import { useScopedI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; -import { NoIntegrationSelectedError } from "../errors"; + +interface QuickFilter { + integrationKinds: string[]; + statuses: ExtendedDownloadClientItem["state"][]; +} //Ratio table for relative width between columns const columnsRatios: Record = { @@ -109,6 +116,18 @@ export default function DownloadClientsWidget({ const [clickedIndex, setClickedIndex] = useState(0); const [opened, { open, close }] = useDisclosure(false); + //User quick settings for filters + const [quickFilters, setQuickFilters] = useState({ integrationKinds: [], statuses: [] }); + const availableStatuses = useMemo(() => { + //Redefine list of available statuses from current items + const statuses = Array.from(new Set(currentItems.flatMap(({ data }) => data.items.map(({ state }) => state)))); + //Reset user filters accordingly to remove unavailable statuses + setQuickFilters(({ integrationKinds: names, statuses: prevStatuses }) => { + return { integrationKinds: names, statuses: prevStatuses.filter((status) => statuses.includes(status)) }; + }); + return statuses; + }, [currentItems]); + //Get API mutation functions const { mutate: mutateResumeItem } = clientApi.widget.downloads.resumeItem.useMutation(); const { mutate: mutatePauseItem } = clientApi.widget.downloads.pauseItem.useMutation(); @@ -165,6 +184,13 @@ export default function DownloadClientsWidget({ progress !== 1)) || (type === "usenet" && ((progress === 1 && options.showCompletedUsenet) || progress !== 1)), ) + //Filter following user quick setting + .filter( + ({ state }) => + (quickFilters.integrationKinds.length === 0 || + quickFilters.integrationKinds.includes(pair.integration.name)) && + (quickFilters.statuses.length === 0 || quickFilters.statuses.includes(state)), + ) //Add extrapolated data and actions if user is allowed interaction .map((item): ExtendedDownloadClientItem => { const received = Math.floor(item.size * item.progress); @@ -200,6 +226,7 @@ export default function DownloadClientsWidget({ options.filterIsWhitelist, options.showCompletedTorrent, options.showCompletedUsenet, + quickFilters, ], ); @@ -636,10 +663,6 @@ export default function DownloadClientsWidget({ { up: 0, down: 0 }, ); - if (integrationIds.length === 0) { - throw new NoIntegrationSelectedError(); - } - if (options.columns.length === 0) return (
@@ -665,7 +688,13 @@ export default function DownloadClientsWidget({ {(globalTraffic.up / globalTraffic.down).toFixed(2)} )} - + @@ -753,10 +782,13 @@ const NormalizedLine = ({ interface ClientsControlProps { clients: ExtendedClientStatus[]; + filters: QuickFilter; + setFilters: (filters: QuickFilter) => void; + availableStatuses: QuickFilter["statuses"]; style?: MantineStyleProp; } -const ClientsControl = ({ clients, style }: ClientsControlProps) => { +const ClientsControl = ({ clients, filters, setFilters, availableStatuses, style }: ClientsControlProps) => { const integrationsStatuses = clients.reduce( (acc, { status, integration: { id }, interact }) => status && interact ? (acc[status.paused ? "paused" : "active"].push(id), acc) : acc, @@ -767,13 +799,61 @@ const ClientsControl = ({ clients, style }: ClientsControlProps) => { clients.reduce((count, { status }) => count + (status?.rates.down ?? 0), 0), "/s", ); + const chipStyle = { + "--chip-fz": "var(--button-fz)", + "--chip-size": "calc(var(--ratio-width) * 0.9)", + "--chip-icon-size": "calc(var(--chip-fz)*2/3)", + "--chip-padding": "var(--chip-fz)", + "--chip-checked-padding": "var(--chip-icon-size)", + "--chip-spacing": "var(--space-size)", + }; const { mutate: mutateResumeQueue } = clientApi.widget.downloads.resume.useMutation(); const { mutate: mutatePauseQueue } = clientApi.widget.downloads.pause.useMutation(); const [opened, { open, close }] = useDisclosure(false); const t = useScopedI18n("widget.downloads"); return ( - + + + + + + + + + {t("items.integration.columnTitle")} + setFilters({ ...filters, integrationKinds: names })} + > + {clients.map(({ integration }) => ( + + {integration.name} + + ))} + + {t("items.state.columnTitle")} + setFilters({ ...filters, statuses: statuses as typeof filters.statuses })} + > + {availableStatuses.map((status) => ( + + {t(`states.${status}`)} + + ))} + + + + + {clients.map((client) => ( ))} @@ -792,7 +872,7 @@ const ClientsControl = ({ clients, style }: ClientsControlProps) => { )}
+ } + sections={[{ value: memory, color: memory > 75 ? "orange" : "green" }]} + /> + + {t("widget.healthMonitoring.cluster.summary.memory")} + {memory.toFixed(1)}% + + + + + ); +}; diff --git a/packages/widgets/src/health-monitoring/cluster/resource-accordion-item.tsx b/packages/widgets/src/health-monitoring/cluster/resource-accordion-item.tsx new file mode 100644 index 000000000..717822e60 --- /dev/null +++ b/packages/widgets/src/health-monitoring/cluster/resource-accordion-item.tsx @@ -0,0 +1,38 @@ +import type { PropsWithChildren } from "react"; +import type { MantineColor } from "@mantine/core"; +import { Accordion, Badge, Group, Text } from "@mantine/core"; + +import type { TablerIcon } from "@homarr/ui"; + +interface ResourceAccordionItemProps { + value: string; + title: string; + icon: TablerIcon; + badge: { + color: MantineColor; + activeCount: number; + totalCount: number; + }; +} + +export const ResourceAccordionItem = ({ + value, + title, + icon: Icon, + badge, + children, +}: PropsWithChildren) => { + return ( + + }> + + {title} + + {badge.activeCount} / {badge.totalCount} + + + + {children} + + ); +}; diff --git a/packages/widgets/src/health-monitoring/cluster/resource-popover.tsx b/packages/widgets/src/health-monitoring/cluster/resource-popover.tsx new file mode 100644 index 000000000..1ce8f54fc --- /dev/null +++ b/packages/widgets/src/health-monitoring/cluster/resource-popover.tsx @@ -0,0 +1,210 @@ +import type { PropsWithChildren } from "react"; +import { Badge, Center, Divider, Flex, Group, List, Popover, RingProgress, Stack, Text } from "@mantine/core"; +import { + IconArrowNarrowDown, + IconArrowNarrowUp, + IconBrain, + IconClockHour3, + IconCpu, + IconDatabase, + IconDeviceLaptop, + IconHeartBolt, + IconNetwork, + IconQuestionMark, + IconServer, +} from "@tabler/icons-react"; +import dayjs from "dayjs"; +import duration from "dayjs/plugin/duration"; + +import { capitalize, humanFileSize } from "@homarr/common"; +import type { ComputeResource, Resource, StorageResource } from "@homarr/integrations/types"; +import { useScopedI18n } from "@homarr/translation/client"; + +dayjs.extend(duration); + +interface ResourcePopoverProps { + item: Resource; +} + +export const ResourcePopover = ({ item, children }: PropsWithChildren) => { + return ( + + {children} + + + + + ); +}; + +export const ResourceTypeEntryDetails = ({ item }: { item: Resource }) => { + const t = useScopedI18n("widget.healthMonitoring.cluster.popover"); + return ( + + + + + + + {item.name} + + {capitalize(item.status)} + + + + {item.type === "node" && } + {item.type === "lxc" && } + {item.type === "qemu" && } + {item.type === "storage" && } + + + + {item.type !== "storage" && } + {item.type === "storage" && } + + ); +}; + +interface RightSectionProps { + label: string; + value: string | number; +} + +const RightSection = ({ label, value }: RightSectionProps) => { + return ( + + + {label} + + + {value} + + + ); +}; + +const ComputeResourceDetails = ({ item }: { item: ComputeResource }) => { + const t = useScopedI18n("widget.healthMonitoring.cluster.popover.detail"); + return ( + + }> + {t("cpu")} - {item.cpu.cores} + + }> + {t("memory")} - {humanFileSize(item.memory.used)} / {humanFileSize(item.memory.total)} + + }> + {t("storage")} - {humanFileSize(item.storage.used)} / {humanFileSize(item.storage.total)} + + }> + {t("uptime")} - {dayjs(dayjs().add(-item.uptime, "seconds")).fromNow(true)} + + {item.haState && ( + }> + {t("haState")} - {capitalize(item.haState)} + + )} + + + + ); +}; + +const StorageResourceDetails = ({ item }: { item: StorageResource }) => { + const t = useScopedI18n("widget.healthMonitoring.cluster.popover.detail"); + const storagePercent = item.total ? (item.used / item.total) * 100 : 0; + return ( + +
+ {storagePercent.toFixed(1)}%} + sections={[{ value: storagePercent, color: storagePercent > 75 ? "orange" : "green" }]} + /> + + + {t("storage")} - {humanFileSize(item.used)} / {humanFileSize(item.total)} + + +
+ + + +
+ ); +}; + +const DiskStats = ({ item }: { item: ComputeResource }) => { + if (!item.storage.read || !item.storage.write) { + return null; + } + return ( + }> + + + {humanFileSize(item.storage.write)} + + + + {humanFileSize(item.storage.read)} + + + + + ); +}; + +const NetStats = ({ item }: { item: ComputeResource }) => { + if (!item.network.in || !item.network.out) { + return null; + } + return ( + }> + + + {humanFileSize(item.network.in)} + + + + {humanFileSize(item.network.out)} + + + + + ); +}; + +const StorageType = ({ item }: { item: StorageResource }) => { + const t = useScopedI18n("widget.healthMonitoring.cluster.popover.detail.storageType"); + if (item.isShared) { + return {t("shared")}; + } else { + return {t("local")}; + } +}; + +const ResourceIcon = ({ type, size }: { type: Resource["type"]; size: number }) => { + switch (type) { + case "node": + return ; + case "lxc": + return ; + case "qemu": + return ; + case "storage": + return ; + default: + console.error(`Unknown resource type: ${type as string}`); + return ; + } +}; diff --git a/packages/widgets/src/health-monitoring/cluster/resource-table.tsx b/packages/widgets/src/health-monitoring/cluster/resource-table.tsx new file mode 100644 index 000000000..bc8226f37 --- /dev/null +++ b/packages/widgets/src/health-monitoring/cluster/resource-table.tsx @@ -0,0 +1,61 @@ +import { Group, Indicator, Popover, Table, Text } from "@mantine/core"; + +import type { Resource } from "@homarr/integrations/types"; +import { useI18n } from "@homarr/translation/client"; + +import { ResourcePopover } from "./resource-popover"; + +interface ResourceTableProps { + type: Resource["type"]; + data: Resource[]; +} + +export const ResourceTable = ({ type, data }: ResourceTableProps) => { + const t = useI18n(); + return ( +
+ + + {t("widget.healthMonitoring.cluster.table.header.name")} + {type !== "storage" ? ( + {t("widget.healthMonitoring.cluster.table.header.cpu")} + ) : null} + {type !== "storage" ? ( + {t("widget.healthMonitoring.cluster.table.header.memory")} + ) : null} + {type === "storage" ? ( + {t("widget.healthMonitoring.cluster.table.header.node")} + ) : null} + + + + {data.map((item) => { + return ( + + + + + {item.type === "storage" ? ( + + ) : ( + <> + + + + )} + + + + ); + })} + +
+ + + {item.name} + + {item.node}{(item.cpu.utilization * 100).toFixed(1)}% + {(item.memory.total ? (item.memory.used / item.memory.total) * 100 : 0).toFixed(1)}% +
+ ); +}; diff --git a/packages/widgets/src/health-monitoring/component.tsx b/packages/widgets/src/health-monitoring/component.tsx index fdde45dfa..0c44f999b 100644 --- a/packages/widgets/src/health-monitoring/component.tsx +++ b/packages/widgets/src/health-monitoring/component.tsx @@ -1,428 +1,61 @@ "use client"; -import { - Avatar, - Box, - Card, - Center, - Divider, - Flex, - Group, - Indicator, - List, - Modal, - Progress, - RingProgress, - Stack, - Text, - Tooltip, -} from "@mantine/core"; -import { useDisclosure, useElementSize } from "@mantine/hooks"; -import { - IconBrain, - IconClock, - IconCpu, - IconCpu2, - IconFileReport, - IconInfoCircle, - IconServer, - IconTemperature, - IconVersions, -} from "@tabler/icons-react"; +import { ScrollArea, Tabs } from "@mantine/core"; import dayjs from "dayjs"; import duration from "dayjs/plugin/duration"; import { clientApi } from "@homarr/api/client"; -import type { TranslationFunction } from "@homarr/translation"; -import { useI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; -import { NoIntegrationSelectedError } from "../errors"; +import { ClusterHealthMonitoring } from "./cluster/cluster-health"; +import { SystemHealthMonitoring } from "./system-health"; dayjs.extend(duration); -export default function HealthMonitoringWidget({ options, integrationIds }: WidgetComponentProps<"healthMonitoring">) { - const t = useI18n(); - const [healthData] = clientApi.widget.healthMonitoring.getHealthStatus.useSuspenseQuery( - { - integrationIds, - }, - { - refetchOnMount: false, - refetchOnWindowFocus: false, - refetchOnReconnect: false, - retry: false, - }, - ); - const [opened, { open, close }] = useDisclosure(false); - const utils = clientApi.useUtils(); +export default function HealthMonitoringWidget(props: WidgetComponentProps<"healthMonitoring">) { + const [integrations] = clientApi.integration.byIds.useSuspenseQuery(props.integrationIds); - clientApi.widget.healthMonitoring.subscribeHealthStatus.useSubscription( - { integrationIds }, - { - onData(data) { - utils.widget.healthMonitoring.getHealthStatus.setData({ integrationIds }, (prevData) => { - if (!prevData) { - return undefined; - } - const newData = prevData.map((item) => - item.integrationId === data.integrationId - ? { ...item, healthInfo: data.healthInfo, timestamp: data.timestamp } - : item, - ); - return newData; - }); - }, - }, - ); + const proxmoxIntegrationId = integrations.find((integration) => integration.kind === "proxmox")?.id; - if (integrationIds.length === 0) { - throw new NoIntegrationSelectedError(); + if (!proxmoxIntegrationId) { + return ; } - return ( - - {healthData.map(({ integrationId, integrationName, healthInfo, updatedAt }) => { - const disksData = matchFileSystemAndSmart(healthInfo.fileSystem, healthInfo.smart); - const memoryUsage = formatMemoryUsage(healthInfo.memAvailable, healthInfo.memUsed); - return ( - - - - - 0 ? "blue" : "gray"} - position="top-end" - size="4cqmin" - label={healthInfo.availablePkgUpdates > 0 ? healthInfo.availablePkgUpdates : undefined} - disabled={!healthInfo.rebootRequired && healthInfo.availablePkgUpdates === 0} - > - - - - - - - - - } - > - {t("widget.healthMonitoring.popover.processor", { cpuModelName: healthInfo.cpuModelName })} - - } - > - {t("widget.healthMonitoring.popover.memory", { memory: memoryUsage.memTotal.GB })} - - } - > - {t("widget.healthMonitoring.popover.memoryAvailable", { - memoryAvailable: memoryUsage.memFree.GB, - percent: memoryUsage.memFree.percent, - })} - - } - > - {t("widget.healthMonitoring.popover.version", { - version: healthInfo.version, - })} - - } - > - {formatUptime(healthInfo.uptime, t)} - - } - > - {t("widget.healthMonitoring.popover.loadAverage")} - - }> - - {t("widget.healthMonitoring.popover.minute")} {healthInfo.loadAverage["1min"]}% - - - {t("widget.healthMonitoring.popover.minutes", { count: 5 })}{" "} - {healthInfo.loadAverage["5min"]}% - - - {t("widget.healthMonitoring.popover.minutes", { count: 15 })}{" "} - {healthInfo.loadAverage["15min"]}% - - - - - - - {options.cpu && } - {healthInfo.cpuTemp && options.cpu && ( - - )} - {options.memory && } - - { - - {t("widget.healthMonitoring.popover.lastSeen", { lastSeen: dayjs(updatedAt).fromNow() })} - - } - - {options.fileSystem && - disksData.map((disk) => { - return ( - - - - - - {disk.deviceName} - - - - - - {options.fahrenheit - ? `${(disk.temperature * 1.8 + 32).toFixed(1)}°F` - : `${disk.temperature}°C`} - - - - - - {disk.overallStatus} - - - - - - - - {t("widget.healthMonitoring.popover.used")} - - - - = 1 - ? `${(Number(disk.available) / 1024 ** 4).toFixed(2)} TiB` - : `${(Number(disk.available) / 1024 ** 3).toFixed(2)} GiB` - } - > - - - {t("widget.healthMonitoring.popover.available")} - - - - - - ); - })} - - ); - })} - + const otherIntegrationIds = integrations + .filter((integration) => integration.kind !== "proxmox") + .map((integration) => integration.id); + if (otherIntegrationIds.length === 0) { + return ; + } + + return ( + + + + + System + + + Cluster + + + + + + + + + + ); } - -export const formatUptime = (uptimeInSeconds: number, t: TranslationFunction) => { - const uptimeDuration = dayjs.duration(uptimeInSeconds, "seconds"); - const days = uptimeDuration.days(); - const hours = uptimeDuration.hours(); - const minutes = uptimeDuration.minutes(); - - return t("widget.healthMonitoring.popover.uptime", { days, hours, minutes }); -}; - -export const progressColor = (percentage: number) => { - if (percentage < 40) return "green"; - else if (percentage < 60) return "yellow"; - else if (percentage < 90) return "orange"; - else return "red"; -}; - -interface FileSystem { - deviceName: string; - used: string; - available: string; - percentage: number; -} - -interface SmartData { - deviceName: string; - temperature: number; - overallStatus: string; -} - -export const matchFileSystemAndSmart = (fileSystems: FileSystem[], smartData: SmartData[]) => { - return fileSystems - .map((fileSystem) => { - const baseDeviceName = fileSystem.deviceName.replace(/[0-9]+$/, ""); - const smartDisk = smartData.find((smart) => smart.deviceName === baseDeviceName); - - return { - deviceName: smartDisk?.deviceName ?? fileSystem.deviceName, - used: fileSystem.used, - available: fileSystem.available, - percentage: fileSystem.percentage, - temperature: smartDisk?.temperature ?? 0, - overallStatus: smartDisk?.overallStatus ?? "", - }; - }) - .sort((fileSystemA, fileSystemB) => fileSystemA.deviceName.localeCompare(fileSystemB.deviceName)); -}; - -const CpuRing = ({ cpuUtilization }: { cpuUtilization: number }) => { - const { width, ref } = useElementSize(); - - return ( - - - {`${cpuUtilization.toFixed(2)}%`} - - - } - sections={[ - { - value: Number(cpuUtilization.toFixed(2)), - color: progressColor(Number(cpuUtilization.toFixed(2))), - }, - ]} - /> - - ); -}; - -const CpuTempRing = ({ fahrenheit, cpuTemp }: { fahrenheit: boolean; cpuTemp: number }) => { - const { width, ref } = useElementSize(); - return ( - - - - {fahrenheit ? `${(cpuTemp * 1.8 + 32).toFixed(1)}°F` : `${cpuTemp.toFixed(1)}°C`} - - - - } - sections={[ - { - value: cpuTemp, - color: progressColor(cpuTemp), - }, - ]} - /> - - ); -}; - -const MemoryRing = ({ available, used }: { available: string; used: string }) => { - const { width, ref } = useElementSize(); - const memoryUsage = formatMemoryUsage(available, used); - - return ( - - - - {memoryUsage.memUsed.GB}GiB - - - - } - sections={[ - { - value: Number(memoryUsage.memUsed.percent), - color: progressColor(Number(memoryUsage.memUsed.percent)), - tooltip: `${memoryUsage.memUsed.percent}%`, - }, - ]} - /> - - ); -}; - -export const formatMemoryUsage = (memFree: string, memUsed: string) => { - const memFreeBytes = Number(memFree); - const memUsedBytes = Number(memUsed); - const totalMemory = memFreeBytes + memUsedBytes; - const memFreeGB = (memFreeBytes / 1024 ** 3).toFixed(2); - const memUsedGB = (memUsedBytes / 1024 ** 3).toFixed(2); - const memFreePercent = Math.round((memFreeBytes / totalMemory) * 100); - const memUsedPercent = Math.round((memUsedBytes / totalMemory) * 100); - const memTotalGB = (totalMemory / 1024 ** 3).toFixed(2); - - return { - memFree: { percent: memFreePercent, GB: memFreeGB }, - memUsed: { percent: memUsedPercent, GB: memUsedGB }, - memTotal: { GB: memTotalGB }, - }; -}; diff --git a/packages/widgets/src/health-monitoring/index.ts b/packages/widgets/src/health-monitoring/index.ts index 970f827f4..2d9c9e895 100644 --- a/packages/widgets/src/health-monitoring/index.ts +++ b/packages/widgets/src/health-monitoring/index.ts @@ -20,6 +20,20 @@ export const { definition, componentLoader } = createWidgetDefinition("healthMon fileSystem: factory.switch({ defaultValue: true, }), + defaultTab: factory.select({ + defaultValue: "system", + options: [ + { value: "system", label: "System" }, + { value: "cluster", label: "Cluster" }, + ] as const, + }), + sectionIndicatorRequirement: factory.select({ + defaultValue: "all", + options: [ + { value: "all", label: "All active" }, + { value: "any", label: "Any active" }, + ] as const, + }), })), supportedIntegrations: getIntegrationKindsByCategory("healthMonitoring"), errors: { diff --git a/packages/widgets/src/health-monitoring/system-health.tsx b/packages/widgets/src/health-monitoring/system-health.tsx new file mode 100644 index 000000000..c2ed07564 --- /dev/null +++ b/packages/widgets/src/health-monitoring/system-health.tsx @@ -0,0 +1,425 @@ +"use client"; + +import { + Avatar, + Box, + Card, + Center, + Divider, + Flex, + Group, + Indicator, + List, + Modal, + Progress, + RingProgress, + Stack, + Text, + Tooltip, +} from "@mantine/core"; +import { useDisclosure, useElementSize } from "@mantine/hooks"; +import { + IconBrain, + IconClock, + IconCpu, + IconCpu2, + IconFileReport, + IconInfoCircle, + IconServer, + IconTemperature, + IconVersions, +} from "@tabler/icons-react"; +import dayjs from "dayjs"; +import duration from "dayjs/plugin/duration"; + +import { clientApi } from "@homarr/api/client"; +import type { TranslationFunction } from "@homarr/translation"; +import { useI18n } from "@homarr/translation/client"; + +import type { WidgetComponentProps } from "../definition"; + +dayjs.extend(duration); + +export const SystemHealthMonitoring = ({ options, integrationIds }: WidgetComponentProps<"healthMonitoring">) => { + const t = useI18n(); + const [healthData] = clientApi.widget.healthMonitoring.getSystemHealthStatus.useSuspenseQuery( + { + integrationIds, + }, + { + refetchOnMount: false, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + retry: false, + }, + ); + const [opened, { open, close }] = useDisclosure(false); + const utils = clientApi.useUtils(); + + clientApi.widget.healthMonitoring.subscribeSystemHealthStatus.useSubscription( + { integrationIds }, + { + onData(data) { + utils.widget.healthMonitoring.getSystemHealthStatus.setData({ integrationIds }, (prevData) => { + if (!prevData) { + return undefined; + } + const newData = prevData.map((item) => + item.integrationId === data.integrationId + ? { ...item, healthInfo: data.healthInfo, updatedAt: data.timestamp } + : item, + ); + return newData; + }); + }, + }, + ); + + return ( + + {healthData.map(({ integrationId, integrationName, healthInfo, updatedAt }) => { + const disksData = matchFileSystemAndSmart(healthInfo.fileSystem, healthInfo.smart); + const memoryUsage = formatMemoryUsage(healthInfo.memAvailable, healthInfo.memUsed); + return ( + + + + + 0 ? "blue" : "gray"} + position="top-end" + size="4cqmin" + label={healthInfo.availablePkgUpdates > 0 ? healthInfo.availablePkgUpdates : undefined} + disabled={!healthInfo.rebootRequired && healthInfo.availablePkgUpdates === 0} + > + + + + + + + + + } + > + {t("widget.healthMonitoring.popover.processor", { cpuModelName: healthInfo.cpuModelName })} + + } + > + {t("widget.healthMonitoring.popover.memory", { memory: memoryUsage.memTotal.GB })} + + } + > + {t("widget.healthMonitoring.popover.memoryAvailable", { + memoryAvailable: memoryUsage.memFree.GB, + percent: memoryUsage.memFree.percent, + })} + + } + > + {t("widget.healthMonitoring.popover.version", { + version: healthInfo.version, + })} + + } + > + {formatUptime(healthInfo.uptime, t)} + + } + > + {t("widget.healthMonitoring.popover.loadAverage")} + + }> + + {t("widget.healthMonitoring.popover.minute")} {healthInfo.loadAverage["1min"]}% + + + {t("widget.healthMonitoring.popover.minutes", { count: 5 })}{" "} + {healthInfo.loadAverage["5min"]}% + + + {t("widget.healthMonitoring.popover.minutes", { count: 15 })}{" "} + {healthInfo.loadAverage["15min"]}% + + + + + + + {options.cpu && } + {healthInfo.cpuTemp && options.cpu && ( + + )} + {options.memory && } + + { + + {t("widget.healthMonitoring.popover.lastSeen", { lastSeen: dayjs(updatedAt).fromNow() })} + + } + + {options.fileSystem && + disksData.map((disk) => { + return ( + + + + + + {disk.deviceName} + + + + + + {options.fahrenheit + ? `${(disk.temperature * 1.8 + 32).toFixed(1)}°F` + : `${disk.temperature}°C`} + + + + + + {disk.overallStatus} + + + + + + + + {t("widget.healthMonitoring.popover.used")} + + + + + = 1 + ? `${(Number(disk.available) / 1024 ** 4).toFixed(2)} TiB` + : `${(Number(disk.available) / 1024 ** 3).toFixed(2)} GiB` + } + > + + + {t("widget.healthMonitoring.popover.available")} + + + + + + ); + })} + + ); + })} + + ); +}; + +export const formatUptime = (uptimeInSeconds: number, t: TranslationFunction) => { + const uptimeDuration = dayjs.duration(uptimeInSeconds, "seconds"); + const months = uptimeDuration.months(); + const days = uptimeDuration.days(); + const hours = uptimeDuration.hours(); + const minutes = uptimeDuration.minutes(); + + return t("widget.healthMonitoring.popover.uptime", { months, days, hours, minutes }); +}; + +export const progressColor = (percentage: number) => { + if (percentage < 40) return "green"; + else if (percentage < 60) return "yellow"; + else if (percentage < 90) return "orange"; + else return "red"; +}; + +interface FileSystem { + deviceName: string; + used: string; + available: string; + percentage: number; +} + +interface SmartData { + deviceName: string; + temperature: number; + overallStatus: string; +} + +export const matchFileSystemAndSmart = (fileSystems: FileSystem[], smartData: SmartData[]) => { + return fileSystems + .map((fileSystem) => { + const baseDeviceName = fileSystem.deviceName.replace(/[0-9]+$/, ""); + const smartDisk = smartData.find((smart) => smart.deviceName === baseDeviceName); + + return { + deviceName: smartDisk?.deviceName ?? fileSystem.deviceName, + used: fileSystem.used, + available: fileSystem.available, + percentage: fileSystem.percentage, + temperature: smartDisk?.temperature ?? 0, + overallStatus: smartDisk?.overallStatus ?? "", + }; + }) + .sort((fileSystemA, fileSystemB) => fileSystemA.deviceName.localeCompare(fileSystemB.deviceName)); +}; + +const CpuRing = ({ cpuUtilization }: { cpuUtilization: number }) => { + const { width, ref } = useElementSize(); + + return ( + + + {`${cpuUtilization.toFixed(2)}%`} + + + } + sections={[ + { + value: Number(cpuUtilization.toFixed(2)), + color: progressColor(Number(cpuUtilization.toFixed(2))), + }, + ]} + /> + + ); +}; + +const CpuTempRing = ({ fahrenheit, cpuTemp }: { fahrenheit: boolean; cpuTemp: number }) => { + const { width, ref } = useElementSize(); + return ( + + + + {fahrenheit ? `${(cpuTemp * 1.8 + 32).toFixed(1)}°F` : `${cpuTemp.toFixed(1)}°C`} + + + + } + sections={[ + { + value: cpuTemp, + color: progressColor(cpuTemp), + }, + ]} + /> + + ); +}; + +const MemoryRing = ({ available, used }: { available: string; used: string }) => { + const { width, ref } = useElementSize(); + const memoryUsage = formatMemoryUsage(available, used); + + return ( + + + + {memoryUsage.memUsed.GB}GiB + + + + } + sections={[ + { + value: Number(memoryUsage.memUsed.percent), + color: progressColor(Number(memoryUsage.memUsed.percent)), + tooltip: `${memoryUsage.memUsed.percent}%`, + }, + ]} + /> + + ); +}; + +export const formatMemoryUsage = (memFree: string, memUsed: string) => { + const memFreeBytes = Number(memFree); + const memUsedBytes = Number(memUsed); + const totalMemory = memFreeBytes + memUsedBytes; + const memFreeGB = (memFreeBytes / 1024 ** 3).toFixed(2); + const memUsedGB = (memUsedBytes / 1024 ** 3).toFixed(2); + const memFreePercent = Math.round((memFreeBytes / totalMemory) * 100); + const memUsedPercent = Math.round((memUsedBytes / totalMemory) * 100); + const memTotalGB = (totalMemory / 1024 ** 3).toFixed(2); + + return { + memFree: { percent: memFreePercent, GB: memFreeGB }, + memUsed: { percent: memUsedPercent, GB: memUsedGB }, + memTotal: { GB: memTotalGB }, + }; +}; diff --git a/packages/widgets/src/iframe/component.tsx b/packages/widgets/src/iframe/component.tsx index b561bd060..3f32742c7 100644 --- a/packages/widgets/src/iframe/component.tsx +++ b/packages/widgets/src/iframe/component.tsx @@ -1,7 +1,7 @@ "use client"; import { Box, Stack, Text, Title } from "@mantine/core"; -import { IconBrowserOff } from "@tabler/icons-react"; +import { IconBrowserOff, IconProtocol } from "@tabler/icons-react"; import { objectEntries } from "@homarr/common"; import { useI18n } from "@homarr/translation/client"; @@ -15,6 +15,9 @@ export default function IFrameWidget({ options, isEditMode }: WidgetComponentPro const allowedPermissions = getAllowedPermissions(permissions); if (embedUrl.trim() === "") return ; + if (!isSupportedProtocol(embedUrl)) { + return ; + } return ( @@ -31,6 +34,17 @@ export default function IFrameWidget({ options, isEditMode }: WidgetComponentPro ); } +const supportedProtocols = ["http", "https"]; + +const isSupportedProtocol = (url: string) => { + try { + const parsedUrl = new URL(url); + return supportedProtocols.map((protocol) => `${protocol}:`).includes(`${parsedUrl.protocol}`); + } catch { + return false; + } +}; + const NoUrl = () => { const t = useI18n(); @@ -42,6 +56,21 @@ const NoUrl = () => { ); }; +const UnsupportedProtocol = () => { + const t = useI18n(); + + return ( + + + + {t("widget.iframe.error.unsupportedProtocol", { + supportedProtocols: supportedProtocols.map((protocol) => protocol).join(", "), + })} + + + ); +}; + const getAllowedPermissions = (permissions: Omit["options"], "embedUrl">) => { return objectEntries(permissions) .filter(([_key, value]) => value) diff --git a/packages/widgets/src/index.tsx b/packages/widgets/src/index.tsx index e2d83563a..b041c11ba 100644 --- a/packages/widgets/src/index.tsx +++ b/packages/widgets/src/index.tsx @@ -21,6 +21,8 @@ import * as indexerManager from "./indexer-manager"; import * as mediaRequestsList from "./media-requests/list"; import * as mediaRequestsStats from "./media-requests/stats"; import * as mediaServer from "./media-server"; +import * as mediaTranscoding from "./media-transcoding"; +import * as minecraftServerStatus from "./minecraft/server-status"; import * as notebook from "./notebook"; import type { WidgetOptionDefinition } from "./options"; import * as rssFeed from "./rssFeed"; @@ -52,6 +54,8 @@ export const widgetImports = { bookmarks, indexerManager, healthMonitoring, + mediaTranscoding, + minecraftServerStatus, } satisfies WidgetImportRecord; export type WidgetImports = typeof widgetImports; diff --git a/packages/widgets/src/indexer-manager/component.tsx b/packages/widgets/src/indexer-manager/component.tsx index 59b29bc7b..1ba4fc273 100644 --- a/packages/widgets/src/indexer-manager/component.tsx +++ b/packages/widgets/src/indexer-manager/component.tsx @@ -7,7 +7,6 @@ import { clientApi } from "@homarr/api/client"; import { useI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; -import { NoIntegrationSelectedError } from "../errors"; export default function IndexerManagerWidget({ options, integrationIds }: WidgetComponentProps<"indexerManager">) { const t = useI18n(); @@ -39,10 +38,6 @@ export default function IndexerManagerWidget({ options, integrationIds }: Widget const iconStyle = { height: "7.5cqmin", width: "7.5cqmin" }; - if (integrationIds.length === 0) { - throw new NoIntegrationSelectedError(); - } - return ( diff --git a/packages/widgets/src/media-requests/list/component.tsx b/packages/widgets/src/media-requests/list/component.tsx index 301c98813..106ca07c4 100644 --- a/packages/widgets/src/media-requests/list/component.tsx +++ b/packages/widgets/src/media-requests/list/component.tsx @@ -9,7 +9,6 @@ import type { ScopedTranslationFunction } from "@homarr/translation"; import { useScopedI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../../definition"; -import { NoIntegrationSelectedError } from "../../errors"; import { NoIntegrationDataError } from "../../errors/no-data-integration"; export default function MediaServerWidget({ @@ -58,8 +57,6 @@ export default function MediaServerWidget({ const { mutate: mutateRequestAnswer } = clientApi.widget.mediaRequests.answerRequest.useMutation(); - if (integrationIds.length === 0) throw new NoIntegrationSelectedError(); - if (mediaRequests.length === 0) throw new NoIntegrationDataError(); return ( diff --git a/packages/widgets/src/media-requests/stats/component.tsx b/packages/widgets/src/media-requests/stats/component.tsx index 021b24509..45fdea032 100644 --- a/packages/widgets/src/media-requests/stats/component.tsx +++ b/packages/widgets/src/media-requests/stats/component.tsx @@ -21,7 +21,6 @@ import type { RequestStats } from "@homarr/integrations/types"; import { useScopedI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../../definition"; -import { NoIntegrationSelectedError } from "../../errors"; import { NoIntegrationDataError } from "../../errors/no-data-integration"; import classes from "./component.module.css"; @@ -43,8 +42,6 @@ export default function MediaServerWidget({ const { width, height, ref } = useElementSize(); - if (integrationIds.length === 0) throw new NoIntegrationSelectedError(); - if (requestStats.users.length === 0 && requestStats.stats.length === 0) throw new NoIntegrationDataError(); //Add processing and available diff --git a/packages/widgets/src/media-server/component.tsx b/packages/widgets/src/media-server/component.tsx index b68b7f09c..6c56a98bc 100644 --- a/packages/widgets/src/media-server/component.tsx +++ b/packages/widgets/src/media-server/component.tsx @@ -1,12 +1,17 @@ "use client"; import { useMemo } from "react"; -import { Avatar, Box, Group, Text } from "@mantine/core"; +import type { MantineStyleProp } from "@mantine/core"; +import { Avatar, Box, Flex, Group, Stack, Text, Title } from "@mantine/core"; +import { IconDeviceAudioTape, IconDeviceTv, IconMovie, IconVideo } from "@tabler/icons-react"; import type { MRT_ColumnDef } from "mantine-react-table"; import { MantineReactTable } from "mantine-react-table"; import { clientApi } from "@homarr/api/client"; +import { getIconUrl, integrationDefs } from "@homarr/definitions"; import type { StreamSession } from "@homarr/integrations"; +import { createModal, useModalAction } from "@homarr/modals"; +import { useScopedI18n } from "@homarr/translation/client"; import { useTranslatedMantineReactTable } from "@homarr/ui/hooks"; import type { WidgetComponentProps } from "../definition"; @@ -29,26 +34,54 @@ export default function MediaServerWidget({ integrationIds, isEditMode }: Widget { accessorKey: "sessionName", header: "Name", + mantineTableHeadCellProps: { + style: { + fontSize: "7cqmin", + padding: "2cqmin", + width: "30%", + }, + }, + Cell: ({ row }) => ( + + {row.original.sessionName} + + ), }, { accessorKey: "user.username", header: "User", + mantineTableHeadCellProps: { + style: { + fontSize: "7cqmin", + padding: "2cqmin", + width: "25%", + }, + }, Cell: ({ row }) => ( - - - {row.original.user.username} + + + {row.original.user.username} ), }, { accessorKey: "currentlyPlaying", // currentlyPlaying.name can be undefined which results in a warning. This is why we use currentlyPlaying instead of currentlyPlaying.name header: "Currently playing", + mantineTableHeadCellProps: { + style: { + fontSize: "7cqmin", + padding: "2cqmin", + width: "45%", + }, + }, Cell: ({ row }) => { if (row.original.currentlyPlaying) { return ( -
- {row.original.currentlyPlaying.name} -
+ + + {row.original.currentlyPlaying.name} + + ); } @@ -83,49 +116,153 @@ export default function MediaServerWidget({ integrationIds, isEditMode }: Widget // Only render the flat list of sessions when the currentStreams change // Otherwise it will always create a new array reference and cause the table to re-render - const flatSessions = useMemo(() => currentStreams.flatMap((pair) => pair.sessions), [currentStreams]); + const flatSessions = useMemo( + () => + currentStreams.flatMap((pair) => + pair.sessions.map((session) => ({ + ...session, + integrationKind: pair.integrationKind, + integrationName: integrationDefs[pair.integrationKind].name, + integrationIcon: getIconUrl(pair.integrationKind), + })), + ), + [currentStreams], + ); + const baseStyle: MantineStyleProp = { + "--total-width": "calc(100cqw / var(--total-width))", + "--ratio-width": "calc(100cqw / var(--total-width))", + "--space-size": "calc(var(--ratio-width) * 0.1)", //Standard gap and spacing value + "--text-fz": "calc(var(--ratio-width) * 0.45)", //General Font Size + "--icon-size": "calc(var(--ratio-width) * 2 / 3)", //Normal icon size + "--mrt-base-background-color": "transparent", + }; + const { openModal } = useModalAction(itemInfoModal); const table = useTranslatedMantineReactTable({ columns, data: flatSessions, - enableRowSelection: false, + enablePagination: false, + enableTopToolbar: false, + enableBottomToolbar: false, + enableSorting: false, + enableColumnActions: false, + enableStickyHeader: false, enableColumnOrdering: false, + enableRowSelection: false, enableFullScreenToggle: false, enableGlobalFilter: false, enableDensityToggle: false, enableFilters: false, - enablePagination: true, - enableSorting: true, enableHiding: false, - enableTopToolbar: false, - enableColumnActions: false, - enableStickyHeader: true, initialState: { density: "xs", }, mantinePaperProps: { - display: "flex", - h: "100%", + flex: 1, withBorder: false, - style: { - flexDirection: "column", - }, + shadow: undefined, }, mantineTableProps: { + className: "media-server-widget-table", style: { tableLayout: "fixed", }, }, mantineTableContainerProps: { style: { - flexGrow: 5, + height: "100%", }, }, + mantineTableBodyCellProps: ({ row }) => ({ + onClick: () => { + openModal({ + item: row.original, + title: + row.original.currentlyPlaying?.type === "movie" ? ( + + ) : row.original.currentlyPlaying?.type === "tv" ? ( + + ) : row.original.currentlyPlaying?.type === "video" ? ( + + ) : ( + + ), + }); + }, + }), + }); + + const uniqueIntegrations = Array.from(new Set(flatSessions.map((session) => session.integrationKind))).map((kind) => { + const session = flatSessions.find((session) => session.integrationKind === kind); + return { + integrationKind: kind, + integrationIcon: session?.integrationIcon, + integrationName: session?.integrationName, + }; }); return ( - + - + + {uniqueIntegrations.map((integration) => ( + + + + {integration.integrationName} + + + ))} + + ); } + +const itemInfoModal = createModal<{ item: StreamSession; title: React.ReactNode }>(({ innerProps }) => { + const t = useScopedI18n("widget.mediaServer.items"); + + return ( + + + {innerProps.title} + {innerProps.item.currentlyPlaying?.name} + + {innerProps.item.currentlyPlaying?.episodeName} + {innerProps.item.currentlyPlaying?.seasonName && ( + <> + {" - "} + {innerProps.item.currentlyPlaying.seasonName} + + )} + + + + + + + ); +}).withOptions({ + defaultTitle() { + return ""; + }, + size: "auto", + centered: true, +}); + +const NormalizedLine = ({ itemKey, value }: { itemKey: string; value: string }) => { + return ( + + {itemKey}: + {value} + + ); +}; diff --git a/packages/widgets/src/media-transcoding/component.tsx b/packages/widgets/src/media-transcoding/component.tsx new file mode 100644 index 000000000..10342ec6a --- /dev/null +++ b/packages/widgets/src/media-transcoding/component.tsx @@ -0,0 +1,115 @@ +"use client"; + +import { useState } from "react"; +import { Center, Divider, Group, Pagination, SegmentedControl, Stack, Text } from "@mantine/core"; +import { IconClipboardList, IconCpu2, IconReportAnalytics } from "@tabler/icons-react"; + +import { clientApi } from "@homarr/api/client"; +import { useI18n } from "@homarr/translation/client"; + +import type { WidgetComponentProps } from "../definition"; +import { HealthCheckStatus } from "./health-check-status"; +import { QueuePanel } from "./panels/queue.panel"; +import { StatisticsPanel } from "./panels/statistics.panel"; +import { WorkersPanel } from "./panels/workers.panel"; + +type Views = "workers" | "queue" | "statistics"; + +export default function MediaTranscodingWidget({ integrationIds, options }: WidgetComponentProps<"mediaTranscoding">) { + const [queuePage, setQueuePage] = useState(1); + const queuePageSize = 10; + const [transcodingData] = clientApi.widget.mediaTranscoding.getDataAsync.useSuspenseQuery( + { + integrationId: integrationIds[0] ?? "", + pageSize: queuePageSize, + page: queuePage, + }, + { + refetchOnMount: false, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + }, + ); + + const [view, setView] = useState(options.defaultView); + const totalQueuePages = Math.ceil((transcodingData.data.queue.totalCount || 1) / queuePageSize); + + const t = useI18n("widget.mediaTranscoding"); + + return ( + + {view === "workers" ? ( + + ) : view === "queue" ? ( + + ) : ( + + )} + + + + + + {t("tab.workers")} + + + ), + value: "workers", + }, + { + label: ( +
+ + + {t("tab.queue")} + +
+ ), + value: "queue", + }, + { + label: ( +
+ + + {t("tab.statistics")} + +
+ ), + value: "statistics", + }, + ]} + value={view} + onChange={(value) => setView(value as Views)} + size="xs" + /> + {view === "queue" && ( + <> + + + + + + + + + + {t("currentIndex", { + start: transcodingData.data.queue.startIndex + 1, + end: transcodingData.data.queue.endIndex + 1, + total: transcodingData.data.queue.totalCount, + })} + + + )} + + + +
+
+ ); +} diff --git a/packages/widgets/src/media-transcoding/health-check-status.tsx b/packages/widgets/src/media-transcoding/health-check-status.tsx new file mode 100644 index 000000000..6491f6289 --- /dev/null +++ b/packages/widgets/src/media-transcoding/health-check-status.tsx @@ -0,0 +1,76 @@ +import type { MantineColor } from "@mantine/core"; +import { Divider, Group, HoverCard, Indicator, RingProgress, Stack, Text } from "@mantine/core"; +import { useColorScheme } from "@mantine/hooks"; +import { IconHeartbeat } from "@tabler/icons-react"; + +import type { TdarrStatistics } from "@homarr/integrations"; +import { useI18n } from "@homarr/translation/client"; + +interface HealthCheckStatusProps { + statistics: TdarrStatistics; +} + +export function HealthCheckStatus(props: HealthCheckStatusProps) { + const colorScheme = useColorScheme(); + const t = useI18n("widget.mediaTranscoding.healthCheck"); + + const indicatorColor = props.statistics.failedHealthCheckCount + ? "red" + : props.statistics.stagedHealthCheckCount + ? "yellow" + : "green"; + + return ( + + + + + + + + + + + {t("title")} + + + + + + + {props.statistics.stagedHealthCheckCount} + + {t("queued")} + + + + {props.statistics.totalHealthCheckCount} + + {t("status.healthy")} + + + + {props.statistics.failedHealthCheckCount} + + {t("status.unhealthy")} + + + + + + ); +} + +function textColor(color: MantineColor, theme: "light" | "dark") { + return `${color}.${theme === "light" ? 8 : 5}`; +} diff --git a/packages/widgets/src/media-transcoding/index.ts b/packages/widgets/src/media-transcoding/index.ts new file mode 100644 index 000000000..c8c6b13fb --- /dev/null +++ b/packages/widgets/src/media-transcoding/index.ts @@ -0,0 +1,22 @@ +import { IconTransform } from "@tabler/icons-react"; + +import { z } from "@homarr/validation"; + +import { createWidgetDefinition } from "../definition"; +import { optionsBuilder } from "../options"; + +export const { componentLoader, definition } = createWidgetDefinition("mediaTranscoding", { + icon: IconTransform, + options: optionsBuilder.from((factory) => ({ + defaultView: factory.select({ + defaultValue: "statistics", + options: [ + { label: "Workers", value: "workers" }, + { label: "Queue", value: "queue" }, + { label: "Statistics", value: "statistics" }, + ], + }), + queuePageSize: factory.number({ defaultValue: 10, validate: z.number().min(1).max(30) }), + })), + supportedIntegrations: ["tdarr"], +}).withDynamicImport(() => import("./component")); diff --git a/packages/widgets/src/media-transcoding/panels/queue.panel.tsx b/packages/widgets/src/media-transcoding/panels/queue.panel.tsx new file mode 100644 index 000000000..9d4d6a680 --- /dev/null +++ b/packages/widgets/src/media-transcoding/panels/queue.panel.tsx @@ -0,0 +1,64 @@ +import { Center, Group, ScrollArea, Table, Text, Title, Tooltip } from "@mantine/core"; +import { IconHeartbeat, IconTransform } from "@tabler/icons-react"; + +import { humanFileSize } from "@homarr/common"; +import type { TdarrQueue } from "@homarr/integrations"; +import { useI18n } from "@homarr/translation/client"; + +interface QueuePanelProps { + queue: TdarrQueue; +} + +export function QueuePanel(props: QueuePanelProps) { + const { queue } = props; + + const t = useI18n("widget.mediaTranscoding.panel.queue"); + + if (queue.array.length === 0) { + return ( +
+ {t("empty")} +
+ ); + } + + return ( + + + + + + + + + + {queue.array.map((item) => ( + + + + + ))} + +
{t("table.file")}{t("table.size")}
+ +
+ {item.type === "transcode" ? ( + + + + ) : ( + + + + )} +
+ + {item.filePath.split("\\").pop()?.split("/").pop() ?? item.filePath} + +
+
+ {humanFileSize(item.fileSize)} +
+
+ ); +} diff --git a/packages/widgets/src/media-transcoding/panels/statistics.panel.tsx b/packages/widgets/src/media-transcoding/panels/statistics.panel.tsx new file mode 100644 index 000000000..93da0c0ce --- /dev/null +++ b/packages/widgets/src/media-transcoding/panels/statistics.panel.tsx @@ -0,0 +1,140 @@ +import type react from "react"; +import type { MantineColor, RingProgressProps } from "@mantine/core"; +import { Box, Center, Grid, Group, RingProgress, Stack, Text, Title, useMantineColorScheme } from "@mantine/core"; +import { IconDatabaseHeart, IconFileDescription, IconHeartbeat, IconTransform } from "@tabler/icons-react"; + +import { humanFileSize } from "@homarr/common"; +import type { TdarrPieSegment, TdarrStatistics } from "@homarr/integrations"; +import { useI18n } from "@homarr/translation/client"; + +const PIE_COLORS: MantineColor[] = ["cyan", "grape", "gray", "orange", "pink"]; + +interface StatisticsPanelProps { + statistics: TdarrStatistics; +} + +export function StatisticsPanel(props: StatisticsPanelProps) { + const t = useI18n("widget.mediaTranscoding.panel.statistics"); + + const allLibs = props.statistics.pies.find((pie) => pie.libraryName === "All"); + + if (!allLibs) { + return ( +
+ {t("empty")} +
+ ); + } + + return ( + + + + + {t("transcodes")} + + + + } + label={t("transcodesCount", { + value: props.statistics.totalTranscodeCount, + })} + /> + + + } + label={t("healthChecksCount", { + value: props.statistics.totalHealthCheckCount, + })} + /> + + + } + label={t("filesCount", { + value: props.statistics.totalFileCount, + })} + /> + + + } + label={t("savedSpace", { + value: humanFileSize(Math.floor(allLibs.savedSpace)), + })} + /> + + + + + {t("healthChecks")} + + + + + + {t("videoCodecs")} + + + + {t("videoContainers")} + + + + {t("videoResolutions")} + + + + ); +} + +function toRingProgressSections(segments: TdarrPieSegment[]): RingProgressProps["sections"] { + const total = segments.reduce((prev, curr) => prev + curr.value, 0); + return segments.map((segment, index) => ({ + value: (segment.value * 100) / total, + tooltip: `${segment.name}: ${segment.value}`, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + color: PIE_COLORS[index % PIE_COLORS.length]!, // Ensures a valid color in the case that index > PIE_COLORS.length + })); +} + +interface StatBoxProps { + icon: react.ReactNode; + label: string; +} + +function StatBox(props: StatBoxProps) { + const { colorScheme } = useMantineColorScheme(); + return ( + ({ + padding: theme.spacing.xs, + border: "1px solid", + borderRadius: theme.radius.md, + borderColor: colorScheme === "dark" ? theme.colors.dark[5] : theme.colors.gray[1], + })} + > + + {props.icon} + {props.label} + + + ); +} diff --git a/packages/widgets/src/media-transcoding/panels/workers.panel.tsx b/packages/widgets/src/media-transcoding/panels/workers.panel.tsx new file mode 100644 index 000000000..961ac5d7c --- /dev/null +++ b/packages/widgets/src/media-transcoding/panels/workers.panel.tsx @@ -0,0 +1,76 @@ +import { Center, Group, Progress, ScrollArea, Table, Text, Title, Tooltip } from "@mantine/core"; +import { IconHeartbeat, IconTransform } from "@tabler/icons-react"; + +import type { TdarrWorker } from "@homarr/integrations"; +import { useI18n } from "@homarr/translation/client"; + +interface WorkersPanelProps { + workers: TdarrWorker[]; +} + +export function WorkersPanel(props: WorkersPanelProps) { + const t = useI18n("widget.mediaTranscoding.panel.workers"); + + if (props.workers.length === 0) { + return ( +
+ {t("empty")} +
+ ); + } + + return ( + + + + + + + + + + + {props.workers.map((worker) => ( + + + + + + ))} + +
{t("table.file")}{t("table.eta")}{t("table.progress")}
+ +
+ {worker.jobType === "transcode" ? ( + + + + ) : ( + + + + )} +
+ + {worker.filePath.split("\\").pop()?.split("/").pop() ?? worker.filePath} + +
+
+ {worker.ETA.startsWith("0:") ? worker.ETA.substring(2) : worker.ETA} + + + {worker.step} + + {Math.round(worker.percentage)}% + +
+
+ ); +} diff --git a/packages/widgets/src/minecraft/server-status/component.tsx b/packages/widgets/src/minecraft/server-status/component.tsx new file mode 100644 index 000000000..bb0be1367 --- /dev/null +++ b/packages/widgets/src/minecraft/server-status/component.tsx @@ -0,0 +1,61 @@ +"use client"; + +import { Box, Flex, Group, Text, Tooltip } from "@mantine/core"; +import { IconUsersGroup } from "@tabler/icons-react"; + +import { clientApi } from "@homarr/api/client"; +import { useScopedI18n } from "@homarr/translation/client"; + +import type { WidgetComponentProps } from "../../definition"; + +export default function MinecraftServerStatusWidget({ options }: WidgetComponentProps<"minecraftServerStatus">) { + const [{ data }] = clientApi.widget.minecraft.getServerStatus.useSuspenseQuery(options); + const utils = clientApi.useUtils(); + clientApi.widget.minecraft.subscribeServerStatus.useSubscription(options, { + onData(data) { + utils.widget.minecraft.getServerStatus.setData(options, { + data, + timestamp: new Date(), + }); + }, + }); + const tStatus = useScopedI18n("widget.minecraftServerStatus.status"); + + const title = options.title.trim().length > 0 ? options.title : options.domain; + + return ( + + + + + + + {title} + + + {data.online && ( + <> + {`minecraft + + + + {data.players.online}/{data.players.max} + + + + )} + + ); +} diff --git a/packages/widgets/src/minecraft/server-status/index.ts b/packages/widgets/src/minecraft/server-status/index.ts new file mode 100644 index 000000000..df4c0e2bc --- /dev/null +++ b/packages/widgets/src/minecraft/server-status/index.ts @@ -0,0 +1,15 @@ +import { IconBrandMinecraft } from "@tabler/icons-react"; + +import { z } from "@homarr/validation"; + +import { createWidgetDefinition } from "../../definition"; +import { optionsBuilder } from "../../options"; + +export const { componentLoader, definition } = createWidgetDefinition("minecraftServerStatus", { + icon: IconBrandMinecraft, + options: optionsBuilder.from((factory) => ({ + title: factory.text({ defaultValue: "" }), + domain: factory.text({ defaultValue: "hypixel.net", validate: z.string().nonempty() }), + isBedrockServer: factory.switch({ defaultValue: false }), + })), +}).withDynamicImport(() => import("./component")); diff --git a/packages/widgets/src/notebook/component.tsx b/packages/widgets/src/notebook/component.tsx index 5231e1db9..a9847eceb 100644 --- a/packages/widgets/src/notebook/component.tsx +++ b/packages/widgets/src/notebook/component.tsx @@ -1,3 +1,5 @@ +"use client"; + import dynamic from "next/dynamic"; import "@mantine/tiptap/styles.css"; diff --git a/packages/widgets/src/smart-home/entity-state/component.tsx b/packages/widgets/src/smart-home/entity-state/component.tsx index 60dcdb9db..766c9aaf8 100644 --- a/packages/widgets/src/smart-home/entity-state/component.tsx +++ b/packages/widgets/src/smart-home/entity-state/component.tsx @@ -8,27 +8,16 @@ import { clientApi } from "@homarr/api/client"; import { useRegisterSpotlightContextActions } from "@homarr/spotlight"; import type { WidgetComponentProps } from "../../definition"; -import { NoIntegrationSelectedError } from "../../errors"; export default function SmartHomeEntityStateWidget({ options, integrationIds, isEditMode, }: WidgetComponentProps<"smartHome-entityState">) { - const integrationId = integrationIds[0]; + // It will always have at least one integration as otherwise the NoIntegrationSelectedError would be thrown in item-content.tsx + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const integrationId = integrationIds[0]!; - if (!integrationId) { - throw new NoIntegrationSelectedError(); - } - - return ; -} - -type InnerComponentProps = Pick, "options" | "isEditMode"> & { - integrationId: string; -}; - -const InnerComponent = ({ options, integrationId, isEditMode }: InnerComponentProps) => { const input = { entityId: options.entityId, integrationId, @@ -103,4 +92,4 @@ const InnerComponent = ({ options, integrationId, isEditMode }: InnerComponentPr ); -}; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 43163e35e..b942d7fb4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + proxmox-api>undici: 7.2.3 + patchedDependencies: pretty-print-error: hash: 4arrfgbz7em6s4gqywse7esg4u @@ -16,27 +19,51 @@ importers: '@homarr/prettier-config': specifier: workspace:^0.1.0 version: link:tooling/prettier + '@semantic-release/changelog': + specifier: ^6.0.3 + version: 6.0.3(semantic-release@24.2.1(typescript@5.7.3)) + '@semantic-release/commit-analyzer': + specifier: ^13.0.1 + version: 13.0.1(semantic-release@24.2.1(typescript@5.7.3)) + '@semantic-release/git': + specifier: ^10.0.1 + version: 10.0.1(semantic-release@24.2.1(typescript@5.7.3)) + '@semantic-release/github': + specifier: ^11.0.1 + version: 11.0.1(semantic-release@24.2.1(typescript@5.7.3)) + '@semantic-release/npm': + specifier: ^12.0.1 + version: 12.0.1(semantic-release@24.2.1(typescript@5.7.3)) + '@semantic-release/release-notes-generator': + specifier: ^14.0.3 + version: 14.0.3(semantic-release@24.2.1(typescript@5.7.3)) '@turbo/gen': specifier: ^2.3.3 - version: 2.3.3(@types/node@22.10.2)(typescript@5.7.2) + version: 2.3.3(@types/node@22.10.7)(typescript@5.7.3) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) + version: 4.3.4(vite@5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) '@vitest/coverage-v8': specifier: ^2.1.8 version: 2.1.8(vitest@2.1.8) '@vitest/ui': specifier: ^2.1.8 version: 2.1.8(vitest@2.1.8) + conventional-changelog-conventionalcommits: + specifier: ^8.0.0 + version: 8.0.0 cross-env: specifier: ^7.0.3 version: 7.0.3 jsdom: - specifier: ^25.0.1 - version: 25.0.1 + specifier: ^26.0.0 + version: 26.0.0 prettier: specifier: ^3.4.2 version: 3.4.2 + semantic-release: + specifier: ^24.2.1 + version: 24.2.1(typescript@5.7.3) testcontainers: specifier: ^10.16.0 version: 10.16.0 @@ -44,14 +71,14 @@ importers: specifier: ^2.3.3 version: 2.3.3 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.7.2)(vite@5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) + version: 5.1.4(typescript@5.7.3)(vite@5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) vitest: specifier: ^2.1.8 - version: 2.1.8(@types/node@22.10.2)(@vitest/ui@2.1.8)(jsdom@25.0.1)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + version: 2.1.8(@types/node@22.10.7)(@vitest/ui@2.1.8)(jsdom@26.0.0)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) apps/nextjs: dependencies: @@ -64,6 +91,9 @@ importers: '@homarr/auth': specifier: workspace:^0.1.0 version: link:../../packages/auth + '@homarr/certificates': + specifier: workspace:^0.1.0 + version: link:../../packages/certificates '@homarr/common': specifier: workspace:^0.1.0 version: link:../../packages/common @@ -80,8 +110,8 @@ importers: specifier: workspace:^0.1.0 version: link:../../packages/form '@homarr/gridstack': - specifier: ^1.11.2 - version: 1.11.2 + specifier: ^1.11.3 + version: 1.11.3 '@homarr/integrations': specifier: workspace:^0.1.0 version: link:../../packages/integrations @@ -97,6 +127,9 @@ importers: '@homarr/notifications': specifier: workspace:^0.1.0 version: link:../../packages/notifications + '@homarr/old-import': + specifier: workspace:^0.1.0 + version: link:../../packages/old-import '@homarr/old-schema': specifier: workspace:^0.1.0 version: link:../../packages/old-schema @@ -122,50 +155,53 @@ importers: specifier: workspace:^0.1.0 version: link:../../packages/widgets '@mantine/colors-generator': - specifier: ^7.15.1 - version: 7.15.1(chroma-js@3.1.2) + specifier: ^7.16.0 + version: 7.16.0(chroma-js@3.1.2) '@mantine/core': - specifier: ^7.15.1 - version: 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/dropzone': + specifier: ^7.16.0 + version: 7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mantine/hooks': - specifier: ^7.15.1 - version: 7.15.1(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(react@19.0.0) '@mantine/modals': - specifier: ^7.15.1 - version: 7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mantine/tiptap': - specifier: ^7.15.1 - version: 7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(@tiptap/extension-link@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3))(@tiptap/react@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(@tiptap/extension-link@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2))(@tiptap/react@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@million/lint': specifier: 1.0.14 version: 1.0.14(rollup@4.21.3)(webpack-sources@3.2.3) '@t3-oss/env-nextjs': specifier: ^0.11.1 - version: 0.11.1(typescript@5.7.2)(zod@3.24.1) + version: 0.11.1(typescript@5.7.3)(zod@3.24.1) '@tabler/icons-react': - specifier: ^3.24.0 - version: 3.24.0(react@19.0.0) + specifier: ^3.28.1 + version: 3.28.1(react@19.0.0) '@tanstack/react-query': - specifier: ^5.62.7 - version: 5.62.7(react@19.0.0) + specifier: ^5.64.1 + version: 5.64.1(react@19.0.0) '@tanstack/react-query-devtools': - specifier: ^5.62.7 - version: 5.62.7(@tanstack/react-query@5.62.7(react@19.0.0))(react@19.0.0) + specifier: ^5.64.1 + version: 5.64.1(@tanstack/react-query@5.64.1(react@19.0.0))(react@19.0.0) '@tanstack/react-query-next-experimental': - specifier: 5.62.7 - version: 5.62.7(@tanstack/react-query@5.62.7(react@19.0.0))(next@14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0))(react@19.0.0) + specifier: 5.64.1 + version: 5.64.1(@tanstack/react-query@5.64.1(react@19.0.0))(next@15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4))(react@19.0.0) '@trpc/client': specifier: next - version: 11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2) + version: 11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3) '@trpc/next': specifier: next - version: 11.0.0-rc.660(@tanstack/react-query@5.62.7(react@19.0.0))(@trpc/client@11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2))(@trpc/react-query@11.0.0-rc.660(@tanstack/react-query@5.62.7(react@19.0.0))(@trpc/client@11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.2))(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(next@14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.2) + version: 11.0.0-rc.700(@tanstack/react-query@5.64.1(react@19.0.0))(@trpc/client@11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3))(@trpc/react-query@11.0.0-rc.700(@tanstack/react-query@5.64.1(react@19.0.0))(@trpc/client@11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3))(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(next@15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) '@trpc/react-query': specifier: next - version: 11.0.0-rc.660(@tanstack/react-query@5.62.7(react@19.0.0))(@trpc/client@11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.2) + version: 11.0.0-rc.700(@tanstack/react-query@5.64.1(react@19.0.0))(@trpc/client@11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3))(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) '@trpc/server': specifier: next - version: 11.0.0-rc.660(typescript@5.7.2) + version: 11.0.0-rc.700(typescript@5.7.3) '@xterm/addon-canvas': specifier: ^0.7.0 version: 0.7.0(@xterm/xterm@5.5.0) @@ -188,20 +224,20 @@ importers: specifier: ^16.4.7 version: 16.4.7 flag-icons: - specifier: ^7.2.3 - version: 7.2.3 + specifier: ^7.3.1 + version: 7.3.1 glob: - specifier: ^11.0.0 - version: 11.0.0 + specifier: ^11.0.1 + version: 11.0.1 jotai: - specifier: ^2.10.3 - version: 2.10.3(@types/react@19.0.1)(react@19.0.0) + specifier: ^2.11.0 + version: 2.11.0(@types/react@19.0.7)(react@19.0.0) mantine-react-table: - specifier: 2.0.0-beta.7 - version: 2.0.0-beta.7(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/dates@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(@tabler/icons-react@3.24.0(react@19.0.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: 2.0.0-beta.8 + version: 2.0.0-beta.8(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/dates@7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(@tabler/icons-react@3.28.1(react@19.0.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next: - specifier: ^14.2.20 - version: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + specifier: 15.1.4 + version: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) postcss-preset-mantine: specifier: ^1.17.0 version: 1.17.0(postcss@8.4.47) @@ -209,26 +245,26 @@ importers: specifier: ^1.29.0 version: 1.29.0 react: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0 react-dom: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0(react@19.0.0) react-error-boundary: - specifier: ^4.1.2 - version: 4.1.2(react@19.0.0) + specifier: ^5.0.0 + version: 5.0.0(react@19.0.0) react-simple-code-editor: specifier: ^0.14.1 version: 0.14.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) sass: - specifier: ^1.83.0 - version: 1.83.0 + specifier: ^1.83.4 + version: 1.83.4 superjson: specifier: 2.2.2 version: 2.2.2 swagger-ui-react: specifier: ^5.18.2 - version: 5.18.2(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 5.18.2(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) use-deep-compare-effect: specifier: ^1.8.1 version: 1.8.1(react@19.0.0) @@ -243,29 +279,29 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript '@types/chroma-js': - specifier: 2.4.4 - version: 2.4.4 + specifier: 3.1.0 + version: 3.1.0 '@types/node': - specifier: ^22.10.2 - version: 22.10.2 + specifier: ^22.10.7 + version: 22.10.7 '@types/prismjs': specifier: ^1.26.5 version: 1.26.5 '@types/react': - specifier: ^19.0.1 - version: 19.0.1 + specifier: 19.0.7 + version: 19.0.7 '@types/react-dom': - specifier: ^19.0.2 - version: 19.0.2(@types/react@19.0.1) + specifier: 19.0.3 + version: 19.0.3(@types/react@19.0.7) '@types/swagger-ui-react': specifier: ^4.18.3 version: 4.18.3 concurrently: - specifier: ^9.1.0 - version: 9.1.0 + specifier: ^9.1.2 + version: 9.1.2 eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 node-loader: specifier: ^2.1.0 version: 2.1.0(webpack@5.94.0) @@ -273,8 +309,8 @@ importers: specifier: ^3.4.2 version: 3.4.2 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 apps/tasks: dependencies: @@ -333,8 +369,8 @@ importers: specifier: 2.2.2 version: 2.2.2 undici: - specifier: 7.1.0 - version: 7.1.0 + specifier: 7.2.3 + version: 7.2.3 devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -346,14 +382,14 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript '@types/node': - specifier: ^22.10.2 - version: 22.10.2 + specifier: ^22.10.7 + version: 22.10.7 dotenv-cli: - specifier: ^7.4.4 - version: 7.4.4 + specifier: ^8.0.0 + version: 8.0.0 eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 prettier: specifier: ^3.4.2 version: 3.4.2 @@ -361,8 +397,8 @@ importers: specifier: 4.19.2 version: 4.19.2 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 apps/websocket: dependencies: @@ -413,14 +449,14 @@ importers: specifier: ^8.5.13 version: 8.5.13 eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 prettier: specifier: ^3.4.2 version: 3.4.2 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/analytics: dependencies: @@ -450,17 +486,20 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/api: dependencies: '@homarr/auth': specifier: workspace:^0.1.0 version: link:../auth + '@homarr/certificates': + specifier: workspace:^0.1.0 + version: link:../certificates '@homarr/common': specifier: workspace:^0.1.0 version: link:../common @@ -479,6 +518,9 @@ importers: '@homarr/definitions': specifier: workspace:^0.1.0 version: link:../definitions + '@homarr/icons': + specifier: workspace:^0.1.0 + version: link:../icons '@homarr/integrations': specifier: workspace:^0.1.0 version: link:../integrations @@ -508,28 +550,34 @@ importers: version: link:../validation '@trpc/client': specifier: next - version: 11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2) + version: 11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3) '@trpc/react-query': specifier: next - version: 11.0.0-rc.660(@tanstack/react-query@5.62.7(react@19.0.0))(@trpc/client@11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.2) + version: 11.0.0-rc.700(@tanstack/react-query@5.64.1(react@19.0.0))(@trpc/client@11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3))(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) '@trpc/server': specifier: next - version: 11.0.0-rc.660(typescript@5.7.2) + version: 11.0.0-rc.700(typescript@5.7.3) dockerode: - specifier: ^4.0.2 + specifier: 4.0.2 version: 4.0.2 + lodash.clonedeep: + specifier: ^4.5.0 + version: 4.5.0 next: - specifier: ^14.2.20 - version: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + specifier: 15.1.4 + version: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) react: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0 + react-dom: + specifier: 19.0.0 + version: 19.0.0(react@19.0.0) superjson: specifier: 2.2.2 version: 2.2.2 trpc-to-openapi: - specifier: ^2.1.0 - version: 2.1.0(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(zod-openapi@2.19.0(zod@3.24.1))(zod@3.24.1) + specifier: ^2.1.2 + version: 2.1.2(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(zod-openapi@2.19.0(zod@3.24.1))(zod@3.24.1) devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -541,17 +589,17 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript '@types/dockerode': - specifier: ^3.3.32 - version: 3.3.32 + specifier: ^3.3.34 + version: 3.3.34 eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 prettier: specifier: ^3.4.2 version: 3.4.2 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/auth: dependencies: @@ -578,7 +626,7 @@ importers: version: link:../validation '@t3-oss/env-nextjs': specifier: ^0.11.1 - version: 0.11.1(typescript@5.7.2)(zod@3.24.1) + version: 0.11.1(typescript@5.7.3)(zod@3.24.1) bcrypt: specifier: ^5.1.1 version: 5.1.1 @@ -586,19 +634,19 @@ importers: specifier: ^0.9.1 version: 0.9.1 ldapts: - specifier: 7.2.2 - version: 7.2.2 + specifier: 7.3.1 + version: 7.3.1 next: - specifier: ^14.2.20 - version: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + specifier: 15.1.4 + version: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) next-auth: specifier: 5.0.0-beta.25 - version: 5.0.0-beta.25(next@14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0))(react@19.0.0) + version: 5.0.0-beta.25(next@15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4))(react@19.0.0) react: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0 react-dom: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0(react@19.0.0) devDependencies: '@homarr/eslint-config': @@ -617,14 +665,39 @@ importers: specifier: 0.9.0 version: 0.9.0 eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 prettier: specifier: ^3.4.2 version: 3.4.2 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 + + packages/certificates: + dependencies: + '@homarr/common': + specifier: workspace:^0.1.0 + version: link:../common + undici: + specifier: 7.2.3 + version: 7.2.3 + devDependencies: + '@homarr/eslint-config': + specifier: workspace:^0.2.0 + version: link:../../tooling/eslint + '@homarr/prettier-config': + specifier: workspace:^0.1.0 + version: link:../../tooling/prettier + '@homarr/tsconfig': + specifier: workspace:^0.1.0 + version: link:../../tooling/typescript + eslint: + specifier: ^9.18.0 + version: 9.18.0 + typescript: + specifier: ^5.7.3 + version: 5.7.3 packages/cli: dependencies: @@ -654,11 +727,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/common: dependencies: @@ -669,14 +742,20 @@ importers: specifier: ^1.11.13 version: 1.11.13 next: - specifier: ^14.2.20 - version: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + specifier: 15.1.4 + version: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) react: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0 - tldts: - specifier: ^6.1.67 - version: 6.1.67 + react-dom: + specifier: 19.0.0 + version: 19.0.0(react@19.0.0) + undici: + specifier: 7.2.3 + version: 7.2.3 + zod: + specifier: ^3.24.1 + version: 3.24.1 devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -688,11 +767,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/cron-job-runner: dependencies: @@ -716,11 +795,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/cron-job-status: dependencies: @@ -738,11 +817,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/cron-jobs: dependencies: @@ -797,6 +876,9 @@ importers: '@homarr/validation': specifier: workspace:^0.1.0 version: link:../validation + semver-parser: + specifier: ^4.1.7 + version: 4.1.7 devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -808,11 +890,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/cron-jobs-core: dependencies: @@ -836,11 +918,11 @@ importers: specifier: ^3.0.11 version: 3.0.11 eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/db: dependencies: @@ -862,27 +944,30 @@ importers: '@paralleldrive/cuid2': specifier: ^2.2.2 version: 2.2.2 + '@t3-oss/env-nextjs': + specifier: ^0.11.1 + version: 0.11.1(typescript@5.7.3)(zod@3.24.1) '@testcontainers/mysql': specifier: ^10.16.0 version: 10.16.0 better-sqlite3: - specifier: ^11.7.0 - version: 11.7.0 + specifier: ^11.8.0 + version: 11.8.0 dotenv: specifier: ^16.4.7 version: 16.4.7 drizzle-kit: - specifier: ^0.30.1 - version: 0.30.1 + specifier: ^0.30.2 + version: 0.30.2 drizzle-orm: - specifier: ^0.38.1 - version: 0.38.1(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@19.0.1)(better-sqlite3@11.7.0)(mysql2@3.11.5)(react@19.0.0) + specifier: ^0.38.4 + version: 0.38.4(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@19.0.7)(better-sqlite3@11.8.0)(mysql2@3.12.0)(react@19.0.0) drizzle-zod: - specifier: ^0.6.0 - version: 0.6.0(drizzle-orm@0.38.1(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@19.0.1)(better-sqlite3@11.7.0)(mysql2@3.11.5)(react@19.0.0))(zod@3.24.1) + specifier: ^0.6.1 + version: 0.6.1(drizzle-orm@0.38.4(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@19.0.7)(better-sqlite3@11.8.0)(mysql2@3.12.0)(react@19.0.0))(zod@3.24.1) mysql2: - specifier: 3.11.5 - version: 3.11.5 + specifier: 3.12.0 + version: 3.12.0 devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -897,11 +982,11 @@ importers: specifier: 7.6.12 version: 7.6.12 dotenv-cli: - specifier: ^7.4.4 - version: 7.4.4 + specifier: ^8.0.0 + version: 8.0.0 eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 prettier: specifier: ^3.4.2 version: 3.4.2 @@ -909,8 +994,8 @@ importers: specifier: 4.19.2 version: 4.19.2 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/definitions: dependencies: @@ -928,14 +1013,17 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/form: dependencies: + '@homarr/common': + specifier: workspace:^0.1.0 + version: link:../common '@homarr/translation': specifier: workspace:^0.1.0 version: link:../translation @@ -943,8 +1031,8 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/form': - specifier: ^7.15.1 - version: 7.15.1(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(react@19.0.0) devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -956,11 +1044,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/icons: dependencies: @@ -984,23 +1072,26 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/integrations: dependencies: '@ctrl/deluge': - specifier: ^7.0.0 - version: 7.0.0 - '@ctrl/qbittorrent': - specifier: ^9.1.0 - version: 9.1.0 - '@ctrl/transmission': specifier: ^7.1.0 version: 7.1.0 + '@ctrl/qbittorrent': + specifier: ^9.2.0 + version: 9.2.0 + '@ctrl/transmission': + specifier: ^7.2.0 + version: 7.2.0 + '@homarr/certificates': + specifier: workspace:^0.1.0 + version: link:../certificates '@homarr/common': specifier: workspace:^0.1.0 version: link:../common @@ -1025,6 +1116,12 @@ importers: '@jellyfin/sdk': specifier: ^0.11.0 version: 0.11.0(axios@1.7.7) + proxmox-api: + specifier: 1.1.1 + version: 1.1.1 + undici: + specifier: 7.2.3 + version: 7.2.3 xml2js: specifier: ^0.6.2 version: 0.6.2 @@ -1042,17 +1139,17 @@ importers: specifier: ^0.4.14 version: 0.4.14 eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/log: dependencies: ioredis: - specifier: 5.4.1 - version: 5.4.1 + specifier: 5.4.2 + version: 5.4.2 superjson: specifier: 2.2.2 version: 2.2.2 @@ -1070,11 +1167,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/modals: dependencies: @@ -1085,13 +1182,13 @@ importers: specifier: workspace:^0.1.0 version: link:../ui '@mantine/core': - specifier: ^7.15.1 - version: 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mantine/hooks': - specifier: ^7.15.1 - version: 7.15.1(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(react@19.0.0) react: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0 devDependencies: '@homarr/eslint-config': @@ -1104,11 +1201,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/modals-collection: dependencies: @@ -1127,6 +1224,107 @@ importers: '@homarr/notifications': specifier: workspace:^0.1.0 version: link:../notifications + '@homarr/old-import': + specifier: workspace:^0.1.0 + version: link:../old-import + '@homarr/old-schema': + specifier: workspace:^0.1.0 + version: link:../old-schema + '@homarr/translation': + specifier: workspace:^0.1.0 + version: link:../translation + '@homarr/ui': + specifier: workspace:^0.1.0 + version: link:../ui + '@homarr/validation': + specifier: workspace:^0.1.0 + version: link:../validation + '@mantine/core': + specifier: ^7.16.0 + version: 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@tabler/icons-react': + specifier: ^3.28.1 + version: 3.28.1(react@19.0.0) + dayjs: + specifier: ^1.11.13 + version: 1.11.13 + next: + specifier: 15.1.4 + version: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) + react: + specifier: 19.0.0 + version: 19.0.0 + react-dom: + specifier: 19.0.0 + version: 19.0.0(react@19.0.0) + devDependencies: + '@homarr/eslint-config': + specifier: workspace:^0.2.0 + version: link:../../tooling/eslint + '@homarr/prettier-config': + specifier: workspace:^0.1.0 + version: link:../../tooling/prettier + '@homarr/tsconfig': + specifier: workspace:^0.1.0 + version: link:../../tooling/typescript + eslint: + specifier: ^9.18.0 + version: 9.18.0 + typescript: + specifier: ^5.7.3 + version: 5.7.3 + + packages/notifications: + dependencies: + '@homarr/ui': + specifier: workspace:^0.1.0 + version: link:../ui + '@mantine/notifications': + specifier: ^7.16.0 + version: 7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@tabler/icons-react': + specifier: ^3.28.1 + version: 3.28.1(react@19.0.0) + devDependencies: + '@homarr/eslint-config': + specifier: workspace:^0.2.0 + version: link:../../tooling/eslint + '@homarr/prettier-config': + specifier: workspace:^0.1.0 + version: link:../../tooling/prettier + '@homarr/tsconfig': + specifier: workspace:^0.1.0 + version: link:../../tooling/typescript + eslint: + specifier: ^9.18.0 + version: 9.18.0 + typescript: + specifier: ^5.7.3 + version: 5.7.3 + + packages/old-import: + dependencies: + '@homarr/common': + specifier: workspace:^0.1.0 + version: link:../common + '@homarr/db': + specifier: workspace:^0.1.0 + version: link:../db + '@homarr/definitions': + specifier: workspace:^0.1.0 + version: link:../definitions + '@homarr/form': + specifier: workspace:^0.1.0 + version: link:../form + '@homarr/log': + specifier: workspace:^0.1.0 + version: link:../log + '@homarr/modals': + specifier: workspace:^0.1.0 + version: link:../modals + '@homarr/notifications': + specifier: workspace:^0.1.0 + version: link:../notifications '@homarr/old-schema': specifier: workspace:^0.1.0 version: link:../old-schema @@ -1140,20 +1338,32 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/core': - specifier: ^7.15.1 - version: 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tabler/icons-react': - specifier: ^3.24.0 - version: 3.24.0(react@19.0.0) - dayjs: - specifier: ^1.11.13 - version: 1.11.13 + specifier: ^7.16.0 + version: 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/hooks': + specifier: ^7.16.0 + version: 7.16.0(react@19.0.0) + adm-zip: + specifier: 0.5.16 + version: 0.5.16 next: - specifier: ^14.2.20 - version: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + specifier: 15.1.4 + version: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) react: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0 + react-dom: + specifier: 19.0.0 + version: 19.0.0(react@19.0.0) + superjson: + specifier: 2.2.2 + version: 2.2.2 + zod: + specifier: ^3.24.1 + version: 3.24.1 + zod-form-data: + specifier: ^2.0.5 + version: 2.0.5(zod@3.24.1) devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -1164,83 +1374,21 @@ importers: '@homarr/tsconfig': specifier: workspace:^0.1.0 version: link:../../tooling/typescript + '@types/adm-zip': + specifier: 0.5.7 + version: 0.5.7 eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 - packages/notifications: - dependencies: - '@homarr/ui': - specifier: workspace:^0.1.0 - version: link:../ui - '@mantine/notifications': - specifier: ^7.15.1 - version: 7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tabler/icons-react': - specifier: ^3.24.0 - version: 3.24.0(react@19.0.0) - devDependencies: - '@homarr/eslint-config': - specifier: workspace:^0.2.0 - version: link:../../tooling/eslint - '@homarr/prettier-config': - specifier: workspace:^0.1.0 - version: link:../../tooling/prettier - '@homarr/tsconfig': - specifier: workspace:^0.1.0 - version: link:../../tooling/typescript - eslint: - specifier: ^9.16.0 - version: 9.16.0 - typescript: - specifier: ^5.7.2 - version: 5.7.2 - - packages/old-import: + packages/old-schema: dependencies: '@homarr/common': specifier: workspace:^0.1.0 version: link:../common - '@homarr/db': - specifier: workspace:^0.1.0 - version: link:../db - '@homarr/definitions': - specifier: workspace:^0.1.0 - version: link:../definitions - '@homarr/log': - specifier: workspace:^0.1.0 - version: link:../log - '@homarr/old-schema': - specifier: workspace:^0.1.0 - version: link:../old-schema - '@homarr/validation': - specifier: workspace:^0.1.0 - version: link:../validation - superjson: - specifier: 2.2.2 - version: 2.2.2 - devDependencies: - '@homarr/eslint-config': - specifier: workspace:^0.2.0 - version: link:../../tooling/eslint - '@homarr/prettier-config': - specifier: workspace:^0.1.0 - version: link:../../tooling/prettier - '@homarr/tsconfig': - specifier: workspace:^0.1.0 - version: link:../../tooling/typescript - eslint: - specifier: ^9.16.0 - version: 9.16.0 - typescript: - specifier: ^5.7.2 - version: 5.7.2 - - packages/old-schema: - dependencies: zod: specifier: ^3.24.1 version: 3.24.1 @@ -1255,11 +1403,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/ping: dependencies: @@ -1280,11 +1428,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/redis: dependencies: @@ -1301,8 +1449,8 @@ importers: specifier: workspace:^ version: link:../log ioredis: - specifier: 5.4.1 - version: 5.4.1 + specifier: 5.4.2 + version: 5.4.2 superjson: specifier: 2.2.2 version: 2.2.2 @@ -1317,11 +1465,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/request-handler: dependencies: @@ -1346,6 +1494,9 @@ importers: dayjs: specifier: ^1.11.13 version: 1.11.13 + octokit: + specifier: ^4.1.0 + version: 4.1.0 pretty-print-error: specifier: ^1.1.2 version: 1.1.2(patch_hash=4arrfgbz7em6s4gqywse7esg4u) @@ -1363,11 +1514,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/server-settings: dependencies: @@ -1388,11 +1539,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/spotlight: dependencies: @@ -1424,26 +1575,29 @@ importers: specifier: workspace:^0.1.0 version: link:../ui '@mantine/core': - specifier: ^7.15.1 - version: 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mantine/hooks': - specifier: ^7.15.1 - version: 7.15.1(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(react@19.0.0) '@mantine/spotlight': - specifier: ^7.15.1 - version: 7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@tabler/icons-react': - specifier: ^3.24.0 - version: 3.24.0(react@19.0.0) + specifier: ^3.28.1 + version: 3.28.1(react@19.0.0) jotai: - specifier: ^2.10.3 - version: 2.10.3(@types/react@18.3.13)(react@19.0.0) + specifier: ^2.11.0 + version: 2.11.0(@types/react@19.0.7)(react@19.0.0) next: - specifier: ^14.2.20 - version: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + specifier: 15.1.4 + version: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) react: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0 + react-dom: + specifier: 19.0.0 + version: 19.0.0(react@19.0.0) use-deep-compare-effect: specifier: ^1.8.1 version: 1.8.1(react@19.0.0) @@ -1458,11 +1612,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/translation: dependencies: @@ -1479,17 +1633,20 @@ importers: specifier: 4.3.1 version: 4.3.1 mantine-react-table: - specifier: 2.0.0-beta.7 - version: 2.0.0-beta.7(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/dates@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(@tabler/icons-react@3.24.0(react@19.0.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: 2.0.0-beta.8 + version: 2.0.0-beta.8(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/dates@7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(@tabler/icons-react@3.28.1(react@19.0.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next: - specifier: ^14.2.20 - version: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + specifier: 15.1.4 + version: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) next-intl: - specifier: 3.26.1 - version: 3.26.1(next@14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0))(react@19.0.0) + specifier: 3.26.3 + version: 3.26.3(next@15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4))(react@19.0.0) react: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0 + react-dom: + specifier: 19.0.0 + version: 19.0.0(react@19.0.0) devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -1501,11 +1658,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/ui: dependencies: @@ -1525,26 +1682,29 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/core': - specifier: ^7.15.1 - version: 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mantine/dates': - specifier: ^7.15.1 - version: 7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mantine/hooks': - specifier: ^7.15.1 - version: 7.15.1(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(react@19.0.0) '@tabler/icons-react': - specifier: ^3.24.0 - version: 3.24.0(react@19.0.0) + specifier: ^3.28.1 + version: 3.28.1(react@19.0.0) mantine-react-table: - specifier: 2.0.0-beta.7 - version: 2.0.0-beta.7(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/dates@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(@tabler/icons-react@3.24.0(react@19.0.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: 2.0.0-beta.8 + version: 2.0.0-beta.8(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/dates@7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(@tabler/icons-react@3.28.1(react@19.0.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next: - specifier: ^14.2.20 - version: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + specifier: 15.1.4 + version: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) react: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0 + react-dom: + specifier: 19.0.0 + version: 19.0.0(react@19.0.0) devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -1559,20 +1719,17 @@ importers: specifier: ^1.0.5 version: 1.0.5 eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/validation: dependencies: '@homarr/definitions': specifier: workspace:^0.1.0 version: link:../definitions - '@homarr/old-schema': - specifier: workspace:^0.1.0 - version: link:../old-schema '@homarr/translation': specifier: workspace:^0.1.0 version: link:../translation @@ -1580,8 +1737,8 @@ importers: specifier: ^3.24.1 version: 3.24.1 zod-form-data: - specifier: ^2.0.2 - version: 2.0.2(zod@3.24.1) + specifier: ^2.0.5 + version: 2.0.5(zod@3.24.1) devDependencies: '@homarr/eslint-config': specifier: workspace:^0.2.0 @@ -1593,11 +1750,11 @@ importers: specifier: workspace:^0.1.0 version: link:../../tooling/typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 packages/widgets: dependencies: @@ -1653,59 +1810,59 @@ importers: specifier: workspace:^0.1.0 version: link:../validation '@mantine/core': - specifier: ^7.15.1 - version: 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@mantine/hooks': - specifier: ^7.15.1 - version: 7.15.1(react@19.0.0) + specifier: ^7.16.0 + version: 7.16.0(react@19.0.0) '@tabler/icons-react': - specifier: ^3.24.0 - version: 3.24.0(react@19.0.0) + specifier: ^3.28.1 + version: 3.28.1(react@19.0.0) '@tiptap/extension-color': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/extension-text-style@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/extension-text-style@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))) '@tiptap/extension-highlight': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) '@tiptap/extension-image': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) '@tiptap/extension-link': - specifier: ^2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) + specifier: ^2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) '@tiptap/extension-table': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) '@tiptap/extension-table-cell': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) '@tiptap/extension-table-header': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) '@tiptap/extension-table-row': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) '@tiptap/extension-task-item': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) '@tiptap/extension-task-list': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) '@tiptap/extension-text-align': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) '@tiptap/extension-text-style': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) '@tiptap/extension-underline': - specifier: 2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) + specifier: 2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) '@tiptap/react': - specifier: ^2.10.3 - version: 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: ^2.11.2 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@tiptap/starter-kit': - specifier: ^2.10.3 - version: 2.10.3 + specifier: ^2.11.2 + version: 2.11.2 clsx: specifier: ^2.1.1 version: 2.1.1 @@ -1713,14 +1870,17 @@ importers: specifier: ^1.11.13 version: 1.11.13 mantine-react-table: - specifier: 2.0.0-beta.7 - version: 2.0.0-beta.7(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/dates@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(@tabler/icons-react@3.24.0(react@19.0.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + specifier: 2.0.0-beta.8 + version: 2.0.0-beta.8(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/dates@7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(@tabler/icons-react@3.28.1(react@19.0.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) next: - specifier: ^14.2.20 - version: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + specifier: 15.1.4 + version: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) react: - specifier: ^19.0.0 + specifier: 19.0.0 version: 19.0.0 + react-dom: + specifier: 19.0.0 + version: 19.0.0(react@19.0.0) video.js: specifier: ^8.21.0 version: 8.21.0 @@ -1738,38 +1898,38 @@ importers: specifier: ^7.3.58 version: 7.3.58 eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 tooling/eslint: dependencies: '@next/eslint-plugin-next': - specifier: ^14.2.20 - version: 14.2.20 + specifier: ^15.1.4 + version: 15.1.4 eslint-config-prettier: - specifier: ^9.1.0 - version: 9.1.0(eslint@9.16.0) + specifier: ^10.0.1 + version: 10.0.1(eslint@9.18.0) eslint-config-turbo: specifier: ^2.3.3 - version: 2.3.3(eslint@9.16.0) + version: 2.3.3(eslint@9.18.0) eslint-plugin-import: specifier: ^2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0)(typescript@5.7.2))(eslint@9.16.0) + version: 2.31.0(@typescript-eslint/parser@8.20.0(eslint@9.18.0)(typescript@5.7.3))(eslint@9.18.0) eslint-plugin-jsx-a11y: specifier: ^6.10.2 - version: 6.10.2(eslint@9.16.0) + version: 6.10.2(eslint@9.18.0) eslint-plugin-react: - specifier: ^7.37.2 - version: 7.37.2(eslint@9.16.0) + specifier: ^7.37.4 + version: 7.37.4(eslint@9.18.0) eslint-plugin-react-hooks: specifier: ^5.1.0 - version: 5.1.0(eslint@9.16.0) + version: 5.1.0(eslint@9.18.0) typescript-eslint: - specifier: ^8.18.0 - version: 8.18.0(eslint@9.16.0)(typescript@5.7.2) + specifier: ^8.20.0 + version: 8.20.0(eslint@9.18.0)(typescript@5.7.3) devDependencies: '@homarr/prettier-config': specifier: workspace:^0.1.0 @@ -1778,19 +1938,19 @@ importers: specifier: workspace:^0.1.0 version: link:../typescript eslint: - specifier: ^9.16.0 - version: 9.16.0 + specifier: ^9.18.0 + version: 9.18.0 typescript: - specifier: ^5.7.2 - version: 5.7.2 + specifier: ^5.7.3 + version: 5.7.3 tooling/github: {} tooling/prettier: dependencies: '@ianvs/prettier-plugin-sort-imports': - specifier: ^4.4.0 - version: 4.4.0(prettier@3.4.2) + specifier: ^4.4.1 + version: 4.4.1(prettier@3.4.2) prettier: specifier: ^3.4.2 version: 3.4.2 @@ -1799,13 +1959,11 @@ importers: specifier: workspace:^0.1.0 version: link:../typescript prettier-plugin-packagejson: - specifier: ^2.5.6 - version: 2.5.6(prettier@3.4.2) + specifier: ^2.5.8 + version: 2.5.8(prettier@3.4.2) typescript: - specifier: ^5.7.2 - version: 5.7.2 - - tooling/semver: {} + specifier: ^5.7.3 + version: 5.7.3 tooling/typescript: {} @@ -1819,6 +1977,9 @@ packages: resolution: {integrity: sha512-2aDL3WUv8hMJb2L3r/PIQWsTLyq7RQr3v9xD16fiz6O8ys1xEyLhhTOv8gxtZvJiTzjTF5pHoArvRdesGL1DMQ==} hasBin: true + '@asamuzakjp/css-color@2.8.2': + resolution: {integrity: sha512-RtWv9jFN2/bLExuZgFFZ0I3pWWeezAHGgrmjqGGWclATl1aDe3yhCUaI0Ilkp6OCk9zX7+FjvDasEX8Q9Rxc5w==} + '@auth/core@0.37.2': resolution: {integrity: sha512-kUvzyvkcd6h1vpeMAojK2y7+PAV5H+0Cc9+ZlKYDFhDY31AlvsB+GW5vNO4qE3Y07KeQgvNO9U0QUx/fN62kBw==} peerDependencies: @@ -1961,6 +2122,10 @@ packages: '@clack/prompts@0.8.2': resolution: {integrity: sha512-6b9Ab2UiZwJYA9iMyboYyW9yJvAO9V753ZhS+DHKEjZRKAxPPOb7MXXu84lsPFG+vZt6FRFniZ8rXi+zCIw4yQ==} + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + '@colors/colors@1.6.0': resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} engines: {node: '>=0.1.90'} @@ -1969,28 +2134,56 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@ctrl/deluge@7.0.0': - resolution: {integrity: sha512-9vnBa2UdYKKC8BXMjLB349LiXL98oyhr8lVGmQq/QhT8RtuB9qzVXHsHPnWjZH1nD24dZM/vOvoG46VWRtRghA==} + '@csstools/color-helpers@5.0.1': + resolution: {integrity: sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==} + engines: {node: '>=18'} + + '@csstools/css-calc@2.1.1': + resolution: {integrity: sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.4 + '@csstools/css-tokenizer': ^3.0.3 + + '@csstools/css-color-parser@3.0.7': + resolution: {integrity: sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.4 + '@csstools/css-tokenizer': ^3.0.3 + + '@csstools/css-parser-algorithms@3.0.4': + resolution: {integrity: sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-tokenizer': ^3.0.3 + + '@csstools/css-tokenizer@3.0.3': + resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==} + engines: {node: '>=18'} + + '@ctrl/deluge@7.1.0': + resolution: {integrity: sha512-A7MUxhVDpblfUloUYCtQTZJXWDUQ6V5oQnWvtNTDhzGjQU4vez2b0uQqzpywyrAkiBtdjWFgm61cESaivJGNXA==} engines: {node: '>=18'} '@ctrl/magnet-link@4.0.2': resolution: {integrity: sha512-wENP7LH4BmCjz+gXVq7Nzz20zMjY/huuG7aDk/yu/LhFdC84e/l8222rCIAo0lwhU451lFcJKLcOmtG6TNrBAQ==} engines: {node: '>=18'} - '@ctrl/qbittorrent@9.1.0': - resolution: {integrity: sha512-mqro5vP94m/evgGSv6fa7Hrip2fhI0F/dMgsTisvi9gChtfXpX1Cj1EwJNzBOiT6yYamEtLJuEe41XLQiXEo/Q==} + '@ctrl/qbittorrent@9.2.0': + resolution: {integrity: sha512-95hcrot7lRPZ/HpDwjDS0qNIDBk015uPX/RastT1AWFGWfZmN/TijUfvwEXHHh6lHziZE2pdT2NQMgvrE1Gg4g==} engines: {node: '>=18'} - '@ctrl/shared-torrent@6.1.0': - resolution: {integrity: sha512-LWhAH6C5Ekp3co8tyRVxAOZhlhHqQmuvc5GXoHcAetIFYbPaKhsqdGEACHtGl549cVO676gQjmvLEgzQnsn56g==} + '@ctrl/shared-torrent@6.2.1': + resolution: {integrity: sha512-0ouXQnBEik6B3LXByiXnDZ6MAj8r9oMEE09q2MkifqSRmGImhZKq7iNbzcGzTn9BI1TU/anwjSOrxjmYV4T5eQ==} engines: {node: '>=18'} '@ctrl/torrent-file@4.1.0': resolution: {integrity: sha512-mC6HdmCrRhhwpthM+OboJvGIywVR05IbdhVSBkfbGslzbQk2xNnx4UOKljV/x2YI2M1DDF3F3o0paIiYd5O0Og==} engines: {node: '>=18'} - '@ctrl/transmission@7.1.0': - resolution: {integrity: sha512-jABXDuyfPWXkX4unhAQRW0cExvcWrI52YsxxO0BseFZHfDwsoOUmHGVln2ODbjqAaTqyKK0Wm+BFfwTOpI5K/w==} + '@ctrl/transmission@7.2.0': + resolution: {integrity: sha512-l0iPcyWxzu0CadILil8s2UGq6EOjkGsFrJCY++4ndJsU0Dw/Cgej/tUkEIu+eKckjylUvVJ/ojVhMpMB8TEhsA==} engines: {node: '>=18'} '@dabh/diagnostics@2.0.3': @@ -2024,6 +2217,9 @@ packages: '@drizzle-team/brocli@0.11.0': resolution: {integrity: sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg==} + '@emnapi/runtime@1.3.1': + resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.is' @@ -2736,24 +2932,24 @@ packages: resolution: {integrity: sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.9.0': - resolution: {integrity: sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==} + '@eslint/core@0.10.0': + resolution: {integrity: sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/eslintrc@3.2.0': resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.16.0': - resolution: {integrity: sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==} + '@eslint/js@9.18.0': + resolution: {integrity: sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.4': resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.2.3': - resolution: {integrity: sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==} + '@eslint/plugin-kit@0.2.5': + resolution: {integrity: sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@extractus/feed-extractor@7.1.3': @@ -2803,8 +2999,8 @@ packages: '@hapi/bourne@3.0.0': resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==} - '@homarr/gridstack@1.11.2': - resolution: {integrity: sha512-WhoXMJtwE7N64Yajn1eoFZ+9JNZpE+6+Eea0uo8sAvVRbEKkJ0kirOK0QL1DW4j16wkvnyHZoxPfdx1DO+hRpQ==} + '@homarr/gridstack@1.11.3': + resolution: {integrity: sha512-7qVEH8DfLBQRJNHBMUTsrt1C1QwPRYcv9hq2vrQ/0M4bZXlxRxMEyUamDNJ1aBMtjDoiOkvirTUJUrZVZV6XBg==} '@hono/node-server@1.13.0': resolution: {integrity: sha512-kz323qIQkNQElEGroo/E9MKPDuIR5pkuk/XEWd50K+cSEKdmdiYx0PKWUdaNY2ecJYngtF+njDMsMKplL6zfEg==} @@ -2832,8 +3028,8 @@ packages: resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} engines: {node: '>=18.18'} - '@ianvs/prettier-plugin-sort-imports@4.4.0': - resolution: {integrity: sha512-f4/e+/ANGk3tHuwRW0uh2YuBR50I4h1ZjGQ+5uD8sWfinHTivQsnieR5cz24t8M6Vx4rYvZ5v/IEKZhYpzQm9Q==} + '@ianvs/prettier-plugin-sort-imports@4.4.1': + resolution: {integrity: sha512-F0/Hrcfpy8WuxlQyAWJTEren/uxKhYonOGY4OyWmwRdeTvkh9mMSCxowZLjNkhwi/2ipqCgtXwwOk7tW0mWXkA==} peerDependencies: '@vue/compiler-sfc': 2.7.x || 3.x prettier: 2 || 3 @@ -2841,6 +3037,111 @@ packages: '@vue/compiler-sfc': optional: true + '@img/sharp-darwin-arm64@0.33.5': + resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.33.5': + resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.0.4': + resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.0.4': + resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.0.4': + resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.0.5': + resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.0.4': + resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.0.4': + resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.33.5': + resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.33.5': + resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-s390x@0.33.5': + resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.33.5': + resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.33.5': + resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.33.5': + resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.33.5': + resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-ia32@0.33.5': + resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.33.5': + resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + '@ioredis/commands@1.2.0': resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} @@ -2889,71 +3190,79 @@ packages: '@libsql/core@0.14.0': resolution: {integrity: sha512-nhbuXf7GP3PSZgdCY2Ecj8vz187ptHlZQ0VRc751oB2C1W8jQUXKKklvt7t1LJiUTQBVJuadF628eUk+3cRi4Q==} - '@mantine/colors-generator@7.15.1': - resolution: {integrity: sha512-xhzJ9HfjOVUH5Y5E5xQX3jepB6pA+gZEAMZtvR7YMPH4akgS0NbJuYuF+A8Cq55rLw58vPTtc3nf6ntfyoCk/w==} + '@mantine/colors-generator@7.16.0': + resolution: {integrity: sha512-mVZB527OPii03DHuiniYufSCOlrPy+nhQyYOrL49qDa5NB/lAccjTGH6QYqQV+Wqdmh9kbpgI13Bo+pwS/iZiQ==} peerDependencies: chroma-js: '>=2.4.2' - '@mantine/core@7.15.1': - resolution: {integrity: sha512-MKHrByqgpu+vzhauX0X9EH+BOgJqyjHwk4E0sfIIX9CXC9pziLMc4aL8pua0KaXiRuQiskTl/DuGX31saHBH5g==} + '@mantine/core@7.16.0': + resolution: {integrity: sha512-lYYwa4Itz77uC8zQzdiKiKdz9Q01NBOYPZsotIKsP/Zqij0qhpsVxoJ8MK3P8IqFyLfThTMmR4sT1qlGfLTA9Q==} peerDependencies: - '@mantine/hooks': 7.15.1 + '@mantine/hooks': 7.16.0 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/dates@7.15.1': - resolution: {integrity: sha512-3WXTq841Em4+e1VLm+t+1mQvfgNkgIAN8/puGg7lljf+Nl6moiI1qekjE1lg2q8EkqI+5uUOgLamlOYX411j5g==} + '@mantine/dates@7.16.0': + resolution: {integrity: sha512-BVPA/3itdAjuX11GMebeS1c5VNruwkkRhCUVVv1F4lBhZqSeL/d8yPb8Iyfdw0tMGIkdxHKT9winG+bXAoF0Kw==} peerDependencies: - '@mantine/core': 7.15.1 - '@mantine/hooks': 7.15.1 + '@mantine/core': 7.16.0 + '@mantine/hooks': 7.16.0 dayjs: '>=1.0.0' react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/form@7.15.1': - resolution: {integrity: sha512-DA2syNlPsG1f+UtnbEG+pf4Pc/DoZUgcdvZn3LsCRxJZYNuwz8qQ16oL/wQ6UIk3klGlJI/RDzRJ9rvn6E28YQ==} + '@mantine/dropzone@7.16.0': + resolution: {integrity: sha512-lZwv96MswNTc0zSt/ObM8uykv2pZbM3eK6pNoA25jn+hZSrcB/TiET15Uhc7k0E/naxvQbZTxeNxQRpN3xrKRQ==} peerDependencies: - react: ^18.x || ^19.x - - '@mantine/hooks@7.15.1': - resolution: {integrity: sha512-jrpjA5JhVSgUi0expfZpvNplMgvwdvrCIcKiDjQ16p/KiWngvTVfmJMtBOVxQ6hWrn500nLmZIDEcTmV9Dvb7g==} - peerDependencies: - react: ^18.x || ^19.x - - '@mantine/modals@7.15.1': - resolution: {integrity: sha512-mKlnzkwqOHO1laeVfILbcPLITF2qRwKbf/aF3GZhHiJVTX0aSEQ5IBL7dBQHhETLsfNp/GLzmOHKyw3zdNUS5g==} - peerDependencies: - '@mantine/core': 7.15.1 - '@mantine/hooks': 7.15.1 + '@mantine/core': 7.16.0 + '@mantine/hooks': 7.16.0 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/notifications@7.15.1': - resolution: {integrity: sha512-HcaePf1Ss0PuLugEsa57w8w5mxh9d/ZeByqn96DXWsN0HtRZ+ElqSFO9nY6G2zQGV7AzB0fqQXhGX4ffdz5zuA==} + '@mantine/form@7.16.0': + resolution: {integrity: sha512-PUxX5v8XMoNwjFdZbns4dDcQf8U9lIfagFsDGz3KKStgsuBcgnn97/MDP6SpsOHV3g7AGEJoF65+ax1fMOkkNA==} peerDependencies: - '@mantine/core': 7.15.1 - '@mantine/hooks': 7.15.1 + react: ^18.x || ^19.x + + '@mantine/hooks@7.16.0': + resolution: {integrity: sha512-8KxrhckesbrV6tyOndm6fJ+jSKA4KX/67ppDFlfYMMbV6Yh+s0zRO4KLi2uCtl6tgckQd2/zDzX3kQk+VYKqDA==} + peerDependencies: + react: ^18.x || ^19.x + + '@mantine/modals@7.16.0': + resolution: {integrity: sha512-2AUFqwuz9JhEnNNjf7Oly4oj1nePKn6QcMKJOQx6Kr1eBcSZRsZ4EmlSONFvfTz/9UJDvm30Hk4HPOPoi0i5fQ==} + peerDependencies: + '@mantine/core': 7.16.0 + '@mantine/hooks': 7.16.0 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/spotlight@7.15.1': - resolution: {integrity: sha512-PtAmuALGrprxjA5NKLYPzvLvlxfC473WI32RF6gPODfZIS8LMSLue+sNuCIDQKeQKNnJOKwatXHH2X/TDGno7w==} + '@mantine/notifications@7.16.0': + resolution: {integrity: sha512-ofwpMLoe/QaXTEqrLNA2vEq4KblacKHLg1xJn7a40irt6uQ6GSlFoLveKjOupiG0xUa+gIbevA1uv3tHJuJ6uA==} peerDependencies: - '@mantine/core': 7.15.1 - '@mantine/hooks': 7.15.1 + '@mantine/core': 7.16.0 + '@mantine/hooks': 7.16.0 react: ^18.x || ^19.x react-dom: ^18.x || ^19.x - '@mantine/store@7.15.1': - resolution: {integrity: sha512-+jwsCE0x0BoeNYhto/Y9PQtHu86BxBNsc3Jw+dNwPP2oeVCbpspopHN+JsTrLR9ZCvsy8N8hxOX7T3ZUGZLYFQ==} + '@mantine/spotlight@7.16.0': + resolution: {integrity: sha512-RZfApZLH7i8ydI5Kj4VD/FSu7Kbp9KAo/KY6bRhpRaFhFLaGRocmCCJ/1RGM/UhMr8gUYwvNa3Be3zStfI7Bvw==} + peerDependencies: + '@mantine/core': 7.16.0 + '@mantine/hooks': 7.16.0 + react: ^18.x || ^19.x + react-dom: ^18.x || ^19.x + + '@mantine/store@7.16.0': + resolution: {integrity: sha512-IeeKk8w+a5Z5sctMUYrLBVVA9173B2oKPP4Rh656eoXH+vz/KCpL/ITnFWrt0Cv9Fyv/V+zm1UyAnUWRdQ6uXA==} peerDependencies: react: ^18.x || ^19.x - '@mantine/tiptap@7.15.1': - resolution: {integrity: sha512-Y2uF4QoKSjMb1b/GmWWwIaXdKrmfdu3qTB7CA21ulONCfm81S13pNtbYYaqk4IR/O2WhQZ2x0UVoGou/VVcMCg==} + '@mantine/tiptap@7.16.0': + resolution: {integrity: sha512-gYiFLoyQ8MSIDPMmi0DG1Ze3kCJHO8tHqbK0yUIKqe8r1Lnzdl86tERqLfUAFlDrQUg2vnNFgpZ8WVfiTHKZgw==} peerDependencies: - '@mantine/core': 7.15.1 - '@mantine/hooks': 7.15.1 + '@mantine/core': 7.16.0 + '@mantine/hooks': 7.16.0 '@tiptap/extension-link': '>=2.1.12' '@tiptap/react': '>=2.1.12' react: ^18.x || ^19.x @@ -2971,62 +3280,56 @@ packages: resolution: {integrity: sha512-u6/kglVwZRu5+GMmtkNlGLqJVkgTl0TtM+hLa9rBg7pldx+5NG5bk45NvL37uZmAr2Xfa1C6qHb7GrFwfP372g==} hasBin: true - '@next/env@14.2.20': - resolution: {integrity: sha512-JfDpuOCB0UBKlEgEy/H6qcBSzHimn/YWjUHzKl1jMeUO+QVRdzmTTl8gFJaNO87c8DXmVKhFCtwxQ9acqB3+Pw==} + '@next/env@15.1.4': + resolution: {integrity: sha512-2fZ5YZjedi5AGaeoaC0B20zGntEHRhi2SdWcu61i48BllODcAmmtj8n7YarSPt4DaTsJaBFdxQAVEVzgmx2Zpw==} - '@next/eslint-plugin-next@14.2.20': - resolution: {integrity: sha512-T0JRi706KLbvR1Uc46t56VtawbhR/igdBagzOrA7G+vv4rvjwnlu/Y4/Iq6X9TDVj5UZjyot4lUdkNd3V2kLhw==} + '@next/eslint-plugin-next@15.1.4': + resolution: {integrity: sha512-HwlEXwCK3sr6zmVGEvWBjW9tBFs1Oe6hTmTLoFQtpm4As5HCdu8jfSE0XJOp7uhfEGLniIx8yrGxEWwNnY0fmQ==} - '@next/swc-darwin-arm64@14.2.20': - resolution: {integrity: sha512-WDfq7bmROa5cIlk6ZNonNdVhKmbCv38XteVFYsxea1vDJt3SnYGgxLGMTXQNfs5OkFvAhmfKKrwe7Y0Hs+rWOg==} + '@next/swc-darwin-arm64@15.1.4': + resolution: {integrity: sha512-wBEMBs+np+R5ozN1F8Y8d/Dycns2COhRnkxRc+rvnbXke5uZBHkUGFgWxfTXn5rx7OLijuUhyfB+gC/ap58dDw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@14.2.20': - resolution: {integrity: sha512-XIQlC+NAmJPfa2hruLvr1H1QJJeqOTDV+v7tl/jIdoFvqhoihvSNykLU/G6NMgoeo+e/H7p/VeWSOvMUHKtTIg==} + '@next/swc-darwin-x64@15.1.4': + resolution: {integrity: sha512-7sgf5rM7Z81V9w48F02Zz6DgEJulavC0jadab4ZsJ+K2sxMNK0/BtF8J8J3CxnsJN3DGcIdC260wEKssKTukUw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@14.2.20': - resolution: {integrity: sha512-pnzBrHTPXIMm5QX3QC8XeMkpVuoAYOmyfsO4VlPn+0NrHraNuWjdhe+3xLq01xR++iCvX+uoeZmJDKcOxI201Q==} + '@next/swc-linux-arm64-gnu@15.1.4': + resolution: {integrity: sha512-JaZlIMNaJenfd55kjaLWMfok+vWBlcRxqnRoZrhFQrhM1uAehP3R0+Aoe+bZOogqlZvAz53nY/k3ZyuKDtT2zQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@14.2.20': - resolution: {integrity: sha512-WhJJAFpi6yqmUx1momewSdcm/iRXFQS0HU2qlUGlGE/+98eu7JWLD5AAaP/tkK1mudS/rH2f9E3WCEF2iYDydQ==} + '@next/swc-linux-arm64-musl@15.1.4': + resolution: {integrity: sha512-7EBBjNoyTO2ipMDgCiORpwwOf5tIueFntKjcN3NK+GAQD7OzFJe84p7a2eQUeWdpzZvhVXuAtIen8QcH71ZCOQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@14.2.20': - resolution: {integrity: sha512-ao5HCbw9+iG1Kxm8XsGa3X174Ahn17mSYBQlY6VGsdsYDAbz/ZP13wSLfvlYoIDn1Ger6uYA+yt/3Y9KTIupRg==} + '@next/swc-linux-x64-gnu@15.1.4': + resolution: {integrity: sha512-9TGEgOycqZFuADyFqwmK/9g6S0FYZ3tphR4ebcmCwhL8Y12FW8pIBKJvSwV+UBjMkokstGNH+9F8F031JZKpHw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@14.2.20': - resolution: {integrity: sha512-CXm/kpnltKTT7945np6Td3w7shj/92TMRPyI/VvveFe8+YE+/YOJ5hyAWK5rpx711XO1jBCgXl211TWaxOtkaA==} + '@next/swc-linux-x64-musl@15.1.4': + resolution: {integrity: sha512-0578bLRVDJOh+LdIoKvgNDz77+Bd85c5JrFgnlbI1SM3WmEQvsjxTA8ATu9Z9FCiIS/AliVAW2DV/BDwpXbtiQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@14.2.20': - resolution: {integrity: sha512-upJn2HGQgKNDbXVfIgmqT2BN8f3z/mX8ddoyi1I565FHbfowVK5pnMEwauvLvaJf4iijvuKq3kw/b6E9oIVRWA==} + '@next/swc-win32-arm64-msvc@15.1.4': + resolution: {integrity: sha512-JgFCiV4libQavwII+kncMCl30st0JVxpPOtzWcAI2jtum4HjYaclobKhj+JsRu5tFqMtA5CJIa0MvYyuu9xjjQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-ia32-msvc@14.2.20': - resolution: {integrity: sha512-igQW/JWciTGJwj3G1ipalD2V20Xfx3ywQy17IV0ciOUBbFhNfyU1DILWsTi32c8KmqgIDviUEulW/yPb2FF90w==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@next/swc-win32-x64-msvc@14.2.20': - resolution: {integrity: sha512-AFmqeLW6LtxeFTuoB+MXFeM5fm5052i3MU6xD0WzJDOwku6SkZaxb1bxjBaRC8uNqTRTSPl0yMFtjNowIVI67w==} + '@next/swc-win32-x64-msvc@15.1.4': + resolution: {integrity: sha512-xxsJy9wzq7FR5SqPCUqdgSXiNXrMuidgckBa8nH9HtjjxsilgcN6VgXF6tZ3uEWuVEadotQJI8/9EQ6guTC4Yw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -3047,6 +3350,153 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@octokit/app@15.1.2': + resolution: {integrity: sha512-6aKmKvqnJKoVK+kx0mLlBMKmQYoziPw4Rd/PWr0j65QVQlrDXlu6hGU8fmTXt7tNkf/DsubdIaTT4fkoWzCh5g==} + engines: {node: '>= 18'} + + '@octokit/auth-app@7.1.4': + resolution: {integrity: sha512-5F+3l/maq9JfWQ4bV28jT2G/K8eu9OJ317yzXPTGe4Kw+lKDhFaS4dQ3Ltmb6xImKxfCQdqDqMXODhc9YLipLw==} + engines: {node: '>= 18'} + + '@octokit/auth-oauth-app@8.1.2': + resolution: {integrity: sha512-3woNZgq5/S6RS+9ZTq+JdymxVr7E0s4EYxF20ugQvgX3pomdPUL5r/XdTY9wALoBM2eHVy4ettr5fKpatyTyHw==} + engines: {node: '>= 18'} + + '@octokit/auth-oauth-device@7.1.2': + resolution: {integrity: sha512-gTOIzDeV36OhVfxCl69FmvJix7tJIiU6dlxuzLVAzle7fYfO8UDyddr9B+o4CFQVaMBLMGZ9ak2CWMYcGeZnPw==} + engines: {node: '>= 18'} + + '@octokit/auth-oauth-user@5.1.2': + resolution: {integrity: sha512-PgVDDPJgZYb3qSEXK4moksA23tfn68zwSAsQKZ1uH6IV9IaNEYx35OXXI80STQaLYnmEE86AgU0tC1YkM4WjsA==} + engines: {node: '>= 18'} + + '@octokit/auth-token@5.1.1': + resolution: {integrity: sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA==} + engines: {node: '>= 18'} + + '@octokit/auth-unauthenticated@6.1.1': + resolution: {integrity: sha512-bGXqdN6RhSFHvpPq46SL8sN+F3odQ6oMNLWc875IgoqcC3qus+fOL2th6Tkl94wvdSTy8/OeHzWy/lZebmnhog==} + engines: {node: '>= 18'} + + '@octokit/core@6.1.2': + resolution: {integrity: sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg==} + engines: {node: '>= 18'} + + '@octokit/core@6.1.3': + resolution: {integrity: sha512-z+j7DixNnfpdToYsOutStDgeRzJSMnbj8T1C/oQjB6Aa+kRfNjs/Fn7W6c8bmlt6mfy3FkgeKBRnDjxQow5dow==} + engines: {node: '>= 18'} + + '@octokit/endpoint@10.1.1': + resolution: {integrity: sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==} + engines: {node: '>= 18'} + + '@octokit/graphql@8.1.1': + resolution: {integrity: sha512-ukiRmuHTi6ebQx/HFRCXKbDlOh/7xEV6QUXaE7MJEKGNAncGI/STSbOkl12qVXZrfZdpXctx5O9X1AIaebiDBg==} + engines: {node: '>= 18'} + + '@octokit/graphql@8.1.2': + resolution: {integrity: sha512-bdlj/CJVjpaz06NBpfHhp4kGJaRZfz7AzC+6EwUImRtrwIw8dIgJ63Xg0OzV9pRn3rIzrt5c2sa++BL0JJ8GLw==} + engines: {node: '>= 18'} + + '@octokit/oauth-app@7.1.5': + resolution: {integrity: sha512-/Y2MiwWDlGUK4blKKfjJiwjzu/FzwKTTTfTZAAQ0QbdBIDEGJPWhOFH6muSN86zaa4tNheB4YS3oWIR2e4ydzA==} + engines: {node: '>= 18'} + + '@octokit/oauth-authorization-url@7.1.1': + resolution: {integrity: sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA==} + engines: {node: '>= 18'} + + '@octokit/oauth-methods@5.1.3': + resolution: {integrity: sha512-M+bDBi5H8FnH0xhCTg0m9hvcnppdDnxUqbZyOkxlLblKpLAR+eT2nbDPvJDp0eLrvJWA1I8OX0KHf/sBMQARRA==} + engines: {node: '>= 18'} + + '@octokit/openapi-types@22.2.0': + resolution: {integrity: sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==} + + '@octokit/openapi-types@23.0.1': + resolution: {integrity: sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==} + + '@octokit/openapi-webhooks-types@8.5.1': + resolution: {integrity: sha512-i3h1b5zpGSB39ffBbYdSGuAd0NhBAwPyA3QV3LYi/lx4lsbZiu7u2UHgXVUR6EpvOI8REOuVh1DZTRfHoJDvuQ==} + + '@octokit/plugin-paginate-graphql@5.2.4': + resolution: {integrity: sha512-pLZES1jWaOynXKHOqdnwZ5ULeVR6tVVCMm+AUbp0htdcyXDU95WbkYdU4R2ej1wKj5Tu94Mee2Ne0PjPO9cCyA==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-paginate-rest@11.3.6': + resolution: {integrity: sha512-zcvqqf/+TicbTCa/Z+3w4eBJcAxCFymtc0UAIsR3dEVoNilWld4oXdscQ3laXamTszUZdusw97K8+DrbFiOwjw==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-paginate-rest@11.4.0': + resolution: {integrity: sha512-ttpGck5AYWkwMkMazNCZMqxKqIq1fJBNxBfsFwwfyYKTf914jKkLF0POMS3YkPBwp5g1c2Y4L79gDz01GhSr1g==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-rest-endpoint-methods@13.3.0': + resolution: {integrity: sha512-LUm44shlmkp/6VC+qQgHl3W5vzUP99ZM54zH6BuqkJK4DqfFLhegANd+fM4YRLapTvPm4049iG7F3haANKMYvQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-retry@7.1.2': + resolution: {integrity: sha512-XOWnPpH2kJ5VTwozsxGurw+svB2e61aWlmk5EVIYZPwFK5F9h4cyPyj9CIKRyMXMHSwpIsI3mPOdpMmrRhe7UQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-retry@7.1.3': + resolution: {integrity: sha512-8nKOXvYWnzv89gSyIvgFHmCBAxfQAOPRlkacUHL9r5oWtp5Whxl8Skb2n3ACZd+X6cYijD6uvmrQuPH/UCL5zQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-throttling@9.3.2': + resolution: {integrity: sha512-FqpvcTpIWFpMMwIeSoypoJXysSAQ3R+ALJhXXSG1HTP3YZOIeLmcNcimKaXxTcws+Sh6yoRl13SJ5r8sXc1Fhw==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': ^6.0.0 + + '@octokit/plugin-throttling@9.4.0': + resolution: {integrity: sha512-IOlXxXhZA4Z3m0EEYtrrACkuHiArHLZ3CvqWwOez/pURNqRuwfoFlTPbN5Muf28pzFuztxPyiUiNwz8KctdZaQ==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': ^6.1.3 + + '@octokit/request-error@6.1.5': + resolution: {integrity: sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ==} + engines: {node: '>= 18'} + + '@octokit/request-error@6.1.6': + resolution: {integrity: sha512-pqnVKYo/at0NuOjinrgcQYpEbv4snvP3bKMRqHaD9kIsk9u1LCpb2smHZi8/qJfgeNqLo5hNW4Z7FezNdEo0xg==} + engines: {node: '>= 18'} + + '@octokit/request@9.1.3': + resolution: {integrity: sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA==} + engines: {node: '>= 18'} + + '@octokit/request@9.1.4': + resolution: {integrity: sha512-tMbOwGm6wDII6vygP3wUVqFTw3Aoo0FnVQyhihh8vVq12uO3P+vQZeo2CKMpWtPSogpACD0yyZAlVlQnjW71DA==} + engines: {node: '>= 18'} + + '@octokit/types@13.6.2': + resolution: {integrity: sha512-WpbZfZUcZU77DrSW4wbsSgTPfKcp286q3ItaIgvSbBpZJlu6mnYXAkjZz6LVZPXkEvLIM8McanyZejKTYUHipA==} + + '@octokit/types@13.7.0': + resolution: {integrity: sha512-BXfRP+3P3IN6fd4uF3SniaHKOO4UXWBfkdR3vA8mIvaoO/wLjGN5qivUtW0QRitBHHMcfC41SLhNVYIZZE+wkA==} + + '@octokit/webhooks-methods@5.1.0': + resolution: {integrity: sha512-yFZa3UH11VIxYnnoOYCVoJ3q4ChuSOk2IVBBQ0O3xtKX4x9bmKb/1t+Mxixv2iUhzMdOl1qeWJqEhouXXzB3rQ==} + engines: {node: '>= 18'} + + '@octokit/webhooks@13.4.2': + resolution: {integrity: sha512-fakbgkCScapQXPxyqx2jZs/Y3jGlyezwUp7ATL7oLAGJ0+SqBKWKstoKZpiQ+REeHutKpYjY9UtxdLSurwl2Tg==} + engines: {node: '>= 18'} + '@panva/hkdf@1.2.1': resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} @@ -3137,6 +3587,11 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@playwright/test@1.49.1': + resolution: {integrity: sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==} + engines: {node: '>=18'} + hasBin: true + '@pnpm/config.env-replace@1.1.0': resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} engines: {node: '>=12.22.0'} @@ -3261,6 +3716,65 @@ packages: '@scarf/scarf@1.4.0': resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + + '@semantic-release/changelog@6.0.3': + resolution: {integrity: sha512-dZuR5qByyfe3Y03TpmCvAxCyTnp7r5XwtHRf/8vD9EAn4ZWbavUX8adMtXYzE86EVh0gyLA7lm5yW4IV30XUag==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0' + + '@semantic-release/commit-analyzer@13.0.1': + resolution: {integrity: sha512-wdnBPHKkr9HhNhXOhZD5a2LNl91+hs8CC2vsAVYxtZH3y0dV3wKn+uZSN61rdJQZ8EGxzWB3inWocBHV9+u/CQ==} + engines: {node: '>=20.8.1'} + peerDependencies: + semantic-release: '>=20.1.0' + + '@semantic-release/error@3.0.0': + resolution: {integrity: sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==} + engines: {node: '>=14.17'} + + '@semantic-release/error@4.0.0': + resolution: {integrity: sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==} + engines: {node: '>=18'} + + '@semantic-release/git@10.0.1': + resolution: {integrity: sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==} + engines: {node: '>=14.17'} + peerDependencies: + semantic-release: '>=18.0.0' + + '@semantic-release/github@11.0.1': + resolution: {integrity: sha512-Z9cr0LgU/zgucbT9cksH0/pX9zmVda9hkDPcgIE0uvjMQ8w/mElDivGjx1w1pEQ+MuQJ5CBq3VCF16S6G4VH3A==} + engines: {node: '>=20.8.1'} + peerDependencies: + semantic-release: '>=24.1.0' + + '@semantic-release/npm@12.0.1': + resolution: {integrity: sha512-/6nntGSUGK2aTOI0rHPwY3ZjgY9FkXmEHbW9Kr+62NVOsyqpKKeP0lrCH+tphv+EsNdJNmqqwijTEnVWUMQ2Nw==} + engines: {node: '>=20.8.1'} + peerDependencies: + semantic-release: '>=20.1.0' + + '@semantic-release/release-notes-generator@14.0.3': + resolution: {integrity: sha512-XxAZRPWGwO5JwJtS83bRdoIhCiYIx8Vhr+u231pQAsdFIAbm19rSVJLdnBN+Avvk7CKvNQE/nJ4y7uqKH6WTiw==} + engines: {node: '>=20.8.1'} + peerDependencies: + semantic-release: '>=20.1.0' + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@sindresorhus/merge-streams@2.3.0': + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} @@ -3351,8 +3865,8 @@ packages: '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - '@swc/helpers@0.5.5': - resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} '@t3-oss/env-core@0.11.1': resolution: {integrity: sha512-MaxOwEoG1ntCFoKJsS7nqwgcxLW1SJw238AJwfJeaz3P/8GtkxXZsPPolsz1AdYvUTbe3XvqZ/VCdfjt+3zmKw==} @@ -3372,39 +3886,39 @@ packages: typescript: optional: true - '@tabler/icons-react@3.24.0': - resolution: {integrity: sha512-m9c7TmlcDmKqvZAasG5rv1YvazZDrVEhNdNFa2d1Bzotc0dh+iceFdiZCEcYPDb5UcRyLAMvOaOC9y/5sfMMWw==} + '@tabler/icons-react@3.28.1': + resolution: {integrity: sha512-KNBpA2kbxr3/2YK5swt7b/kd/xpDP1FHYZCxDFIw54tX8slELRFEf95VMxsccQHZeIcUbdoojmUUuYSbt/sM5Q==} peerDependencies: react: '>= 16' - '@tabler/icons@3.24.0': - resolution: {integrity: sha512-qNis9e90QcdxAGV3wNIeX0Ba2R7ktm0cnqOToKHJfC2kj3fvJwEVLsw63K0/fm7NW8rSZjDSTQRmMnSg8g/wrg==} + '@tabler/icons@3.28.1': + resolution: {integrity: sha512-h7nqKEvFooLtFxhMOC1/2eiV+KRXhBUuDUUJrJlt6Ft6tuMw2eU/9GLQgrTk41DNmIEzp/LI83K9J9UUU8YBYQ==} '@tanstack/match-sorter-utils@8.19.4': resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==} engines: {node: '>=12'} - '@tanstack/query-core@5.62.7': - resolution: {integrity: sha512-fgpfmwatsrUal6V+8EC2cxZIQVl9xvL7qYa03gsdsCy985UTUlS4N+/3hCzwR0PclYDqisca2AqR1BVgJGpUDA==} + '@tanstack/query-core@5.64.1': + resolution: {integrity: sha512-978Wx4Wl4UJZbmvU/rkaM9cQtXXrbhK0lsz/UZhYIbyKYA8E4LdomTwyh2GHZ4oU0BKKoDH4YlKk2VscCUgNmg==} - '@tanstack/query-devtools@5.61.4': - resolution: {integrity: sha512-21Tw+u8E3IJJj4A/Bct4H0uBaDTEu7zBrR79FeSyY+mS2gx5/m316oDtJiKkILc819VSTYt+sFzODoJNcpPqZQ==} + '@tanstack/query-devtools@5.62.16': + resolution: {integrity: sha512-3ff6UBJr0H3nIhfLSl9911rvKqXf0u4B58jl0uYdDWLqPk9pCvYIbxC35cGxK2+8INl4IaFVUHb/IdgWrNkg3Q==} - '@tanstack/react-query-devtools@5.62.7': - resolution: {integrity: sha512-wxXsdTZJRs//hMtJMU5aNlUaTclRFPqLvDNeWbRj8YpGD3aoo4zyu53W55W2DY16+ycg3fti21uCW4N9oyj91w==} + '@tanstack/react-query-devtools@5.64.1': + resolution: {integrity: sha512-8ajcGE3wXYlb4KuJnkFYkJwJKc/qmPNTpQD7YTgLRMBPTGGp1xk7VMzxL87DoXuweO8luplUUblJJ3noVs/luQ==} peerDependencies: - '@tanstack/react-query': ^5.62.7 + '@tanstack/react-query': ^5.64.1 react: ^18 || ^19 - '@tanstack/react-query-next-experimental@5.62.7': - resolution: {integrity: sha512-9f+VpQ3P7ta86frcpZVYDcaYCAktQ/ccp7nrNUWdRnHkcVQ/kQJKwGCCxBPoV7/K/PmeWDZDR4COqcQi7bIGnw==} + '@tanstack/react-query-next-experimental@5.64.1': + resolution: {integrity: sha512-23YAN+F8KiyVClBbzy4yUazWZRuoyuQnMlQIABPQCVQUx6+mOtVviwPlgXY47q1yMHRNnUwbKSVGct2JFqkeaw==} peerDependencies: - '@tanstack/react-query': ^5.62.7 + '@tanstack/react-query': ^5.64.1 next: ^13 || ^14 || ^15 react: ^18 || ^19 - '@tanstack/react-query@5.62.7': - resolution: {integrity: sha512-+xCtP4UAFDTlRTYyEjLx0sRtWyr5GIk7TZjZwBu4YaNahi3Rt2oMyRqfpfVrtwsqY2sayP4iXVCwmC+ZqqFmuw==} + '@tanstack/react-query@5.64.1': + resolution: {integrity: sha512-vW5ggHpIO2Yjj44b4sB+Fd3cdnlMJppXRBJkEHvld6FXh3j5dwWJoQo7mGtKI2RbSFyiyu/PhGAy0+Vv5ev9Eg==} peerDependencies: react: ^18 || ^19 @@ -3415,257 +3929,257 @@ packages: react: '>=16.8' react-dom: '>=16.8' - '@tanstack/react-virtual@3.10.8': - resolution: {integrity: sha512-VbzbVGSsZlQktyLrP5nxE+vE1ZR+U0NFAWPbJLoG2+DKPwd2D7dVICTVIIaYlJqX1ZCEnYDbaOpmMwbsyhBoIA==} + '@tanstack/react-virtual@3.11.2': + resolution: {integrity: sha512-OuFzMXPF4+xZgx8UzJha0AieuMihhhaWG0tCqpp6tDzlFwOmNBPYMuLOtMJ1Tr4pXLHmgjcWhG6RlknY2oNTdQ==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@tanstack/table-core@8.20.5': resolution: {integrity: sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==} engines: {node: '>=12'} - '@tanstack/virtual-core@3.10.8': - resolution: {integrity: sha512-PBu00mtt95jbKFi6Llk9aik8bnR3tR/oQP1o3TSi+iG//+Q2RTIzCEgKkHG8BB86kxMNW6O8wku+Lmi+QFR6jA==} + '@tanstack/virtual-core@3.11.2': + resolution: {integrity: sha512-vTtpNt7mKCiZ1pwU9hfKPhpdVO2sVzFQsxoVBGtOSHxlrRRzYr8iQ2TlwbAcRYCcEiZ9ECAM8kBzH0v2+VzfKw==} '@testcontainers/mysql@10.16.0': resolution: {integrity: sha512-GyxWqKfpY13lUrTEBmkKrAXyN7RZ//ntMdY/5Eyo/SukDM9LNGu3j5aNuDTGlYr4AEMJuzJ8CHxqUDAFGnCB/w==} - '@tiptap/core@2.10.3': - resolution: {integrity: sha512-wAG/0/UsLeZLmshWb6rtWNXKJftcmnned91/HLccHVQAuQZ1UWH+wXeQKu/mtodxEO7JcU2mVPR9mLGQkK0McQ==} + '@tiptap/core@2.11.2': + resolution: {integrity: sha512-Z437c/sQg31yrRVgLJVkQuih+7Og5tjRx6FE/zE47QgEayqQ9yXH0LrTAbPiY6IfY1X+f2A0h3e5Y/WGD6rC3Q==} peerDependencies: '@tiptap/pm': ^2.7.0 - '@tiptap/extension-blockquote@2.10.3': - resolution: {integrity: sha512-u9Mq4r8KzoeGVT8ms6FQDIMN95dTh3TYcT7fZpwcVM96mIl2Oyt+Bk66mL8z4zuFptfRI57Cu9QdnHEeILd//w==} + '@tiptap/extension-blockquote@2.11.2': + resolution: {integrity: sha512-5XeU1o5UfjMCFX3AwgeErwDKlpUr5YPhta2tQqNsQUQ7QvumIdK/3apNT15/d8pySAjdAphDWEd/CZ2di5hq6A==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-bold@2.10.3': - resolution: {integrity: sha512-xnF1tS2BsORenr11qyybW120gHaeHKiKq+ZOP14cGA0MsriKvWDnaCSocXP/xMEYHy7+2uUhJ0MsKkHVj4bPzQ==} + '@tiptap/extension-bold@2.11.2': + resolution: {integrity: sha512-pSls6UnKiPMm2c0m1viuZ0aFexxUmTRm17vDA2Gy5PhRm5qSsnHlSxyEuEcKNOi/rIx+oJehvG1oO4uI+kmCKg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-bubble-menu@2.10.3': - resolution: {integrity: sha512-e9a4yMjQezuKy0rtyyzxbV2IAE1bm1PY3yoZEFrcaY0o47g1CMUn2Hwe+9As2HdntEjQpWR7NO1mZeKxHlBPYA==} + '@tiptap/extension-bubble-menu@2.11.2': + resolution: {integrity: sha512-G+m7JLhe6SGcDugm8q3RXVLVnCm4t67FGNlOLRzq25VNgD7FDNwjgISp04W+qcJa0+Z5cbQt/4naUji5QEH97A==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-bullet-list@2.10.3': - resolution: {integrity: sha512-PTkwJOVlHi4RR4Wrs044tKMceweXwNmWA6EoQ93hPUVtQcwQL990Es5Izp+i88twTPLuGD9dH+o9QDyH9SkWdA==} + '@tiptap/extension-bullet-list@2.11.2': + resolution: {integrity: sha512-zqZYT7lmmivEDEO+6w5bl5kV3UP1L2dw5mksyMGtxpvoDgbFHZ85+ron6SeHee8C7vJc6aIptc1p6NxIS5/l0A==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-code-block@2.10.3': - resolution: {integrity: sha512-yiDVNg22fYkzsFk5kBlDSHcjwVJgajvO/M5fDXA+Hfxwo2oNcG6aJyyHXFe+UaXTVjdkPej0J6kcMKrTMCiFug==} + '@tiptap/extension-code-block@2.11.2': + resolution: {integrity: sha512-O6gVfql3uFZNq9yaUDa98VgV58BqaUSeOUnhZwLzpB/4VlqzTyW6/kvFxhKcSp7f+GmrMQaV4PXRs+tZcq6EFw==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-code@2.10.3': - resolution: {integrity: sha512-JyLbfyY3cPctq9sVdpcRWTcoUOoq3/MnGE1eP6eBNyMTHyBPcM9TPhOkgj+xkD1zW/884jfelB+wa70RT/AMxQ==} + '@tiptap/extension-code@2.11.2': + resolution: {integrity: sha512-G8vvb17QAYQij3haz9RoDvArK1LSOZHqGzQ2dJ3/d0W5oqOyUrTnseN66fRZjWhBT3pns0VL2erwe/NBIqLOIw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-color@2.10.3': - resolution: {integrity: sha512-FC2hPMSQ4w9UmO9kJCAdoU7gHpDbJ6MeJAmikB9EPp16dbGwFLrZm9TZ/4pv74fGfVm0lv720316ALOEgPEDjQ==} + '@tiptap/extension-color@2.11.2': + resolution: {integrity: sha512-KUfASlEXrZeioBeSnpQWmCIiWtVaHDXJ+ZD0giSGSTQ4JwqdsIYZd8HpUrQjsfTkrqxW13zxQ1VklfvSPM8PQA==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/extension-text-style': ^2.7.0 - '@tiptap/extension-document@2.10.3': - resolution: {integrity: sha512-6i8+xbS2zB6t8iFzli1O/QB01MmwyI5Hqiiv4m5lOxqavmJwLss2sRhoMC2hB3CyFg5UmeODy/f/RnI6q5Vixg==} + '@tiptap/extension-document@2.11.2': + resolution: {integrity: sha512-/EZhIAN1x7DYgGM0xv7y7wo5ceBmHb0+rOIPuBerVFeTn+VcC3tST/Q64bdvcxgNe2E59Ti0CUdYEA51wc2u5Q==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-dropcursor@2.10.3': - resolution: {integrity: sha512-wzWf82ixWzZQr0hxcf/A0ul8NNxgy1N63O+c56st6OomoLuKUJWOXF+cs9O7V+/5rZKWdbdYYoRB5QLvnDBAlQ==} + '@tiptap/extension-dropcursor@2.11.2': + resolution: {integrity: sha512-HbXC9cMVZUY3kyKwbDtVH452CY1qlyLbIvTaN0+dxkFgcVeQZZtfIxU7DwMmqCDmDnsh0CdDqUgUvcXS2UQTwA==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-floating-menu@2.10.3': - resolution: {integrity: sha512-Prg8rYLxeyzHxfzVu1mDkkUWMnD9ZN3y370O/1qy55e+XKVw9jFkTSuz0y0+OhMJG6bulYpDUMtb+N3+2xOWlQ==} + '@tiptap/extension-floating-menu@2.11.2': + resolution: {integrity: sha512-DoFGgguE24rxPkZTD7sH3GFi9E3JKQGeGw0sFTwXx1ZFnyCtqbLcPOfT4THlvUEcixt68Mk48M1NTFVOGn/dyA==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-gapcursor@2.10.3': - resolution: {integrity: sha512-FskZi2DqDSTH1WkgLF2OLy0xU7qj3AgHsKhVsryeAtld4jAK5EsonneWgaipbz0e/MxuIvc1oyacfZKABpLaNg==} + '@tiptap/extension-gapcursor@2.11.2': + resolution: {integrity: sha512-ssJOrcc8dzlo5/Qq3+EixASDHTj3mqCyAv7Ohed1QYEYr+TsSpsTbjR0eMLjWHlgbt24TXL2Wr0ldjYCU8T1ZA==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-hard-break@2.10.3': - resolution: {integrity: sha512-2rFlimUKAgKDwT6nqAMtPBjkrknQY8S7oBNyIcDOUGyFkvbDUl3Jd0PiC929S5F3XStJRppnMqhpNDAlWmvBLA==} + '@tiptap/extension-hard-break@2.11.2': + resolution: {integrity: sha512-FNcXemfuwkiP4drZ9m90BC6GD4nyikfYHYEUyYuVd74Mm6w5vXpueWXus3mUcdT78xTs1XpQVibDorilLu7X8w==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-heading@2.10.3': - resolution: {integrity: sha512-AlxXXPCWIvw8hQUDFRskasj32iMNB8Sb19VgyFWqwvntGs2/UffNu8VdsVqxD2HpZ0g5rLYCYtSW4wigs9R3og==} + '@tiptap/extension-heading@2.11.2': + resolution: {integrity: sha512-y/wAEXYB0a8y5WmSYGCIXAhus1ydudn0pokKIzT/OD00XutAVh14qOB5h/+m8iXwGU/UYMP7SUCtK82txZqwKA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-highlight@2.10.3': - resolution: {integrity: sha512-srMOdpUTcp1yPGmUqgKOkbmTpCYOF6Q/8CnquDkhrvK7Gyphj+n8TocrKiloaRYZKcoQWtmb+kcVPaHhHMzsWQ==} + '@tiptap/extension-highlight@2.11.2': + resolution: {integrity: sha512-ztq2lGthTIY/zPYtdYrG7+0dc4R4abkZqDVAmLxkFcwjs/mejq7nMG7WM2Unn2cIGo96m8Ibz/UtoOPJDt/+/Q==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-history@2.10.3': - resolution: {integrity: sha512-HaSiMdx9Im9Pb9qGlVud7W8bweRDRMez33Uzs5a2x0n1RWkelfH7TwYs41Y3wus8Ujs7kw6qh7jyhvPpQBKaSA==} + '@tiptap/extension-history@2.11.2': + resolution: {integrity: sha512-BamS6YjKsETgP7msmm0oIpqmNSLJWbivm3XurR3uSUqJZYrQo1Fv+No4HAR7eAACxoOnYGcDmYsrombRVs9lxw==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-horizontal-rule@2.10.3': - resolution: {integrity: sha512-1a2IWhD00tgUNg/91RLnBvfENL7DLCui5L245+smcaLu+OXOOEpoBHawx59/M4hEpsjqvRRM79TzO9YXfopsPw==} + '@tiptap/extension-horizontal-rule@2.11.2': + resolution: {integrity: sha512-R7MkTQzxkBy0bXJfq6L+6ax01/hmTEUvPPoyjwDSfU1Ktc1ihBJGUdTNtohT1KoQGQYt2d9khBohVspsXoCmFw==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-image@2.10.3': - resolution: {integrity: sha512-YIjAF5CwDkMe28OQ5pvnmdRgbJ9JcGMIHY1kyqNunSf2iwphK+6SWz9UEIkDFiT7AsRZySqxFSq93iK1XyTifw==} + '@tiptap/extension-image@2.11.2': + resolution: {integrity: sha512-Ag+Arj6sclTqhvR+v5I2UD5e2lsWTcXLj0aS2aEsfGpytltk6rcLj6iDjx/SmJrE1BN8ognJsdzmFdZF/rNLpg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-italic@2.10.3': - resolution: {integrity: sha512-wAiO6ZxoHx2H90phnKttLWGPjPZXrfKxhOCsqYrK8BpRByhr48godOFRuGwYnKaiwoVjpxc63t+kDJDWvqmgMw==} + '@tiptap/extension-italic@2.11.2': + resolution: {integrity: sha512-652oTa+iDiR7sMtmePSy+303HSNJxvxmV/6IvQoMdffJU0oPiWcWnCCL0qrWgtHh15dplj36EtB/znENWbvVOw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-link@2.10.3': - resolution: {integrity: sha512-8esKlkZBzEiNcpt7I8Cd6l1mWmCc/66pPbUq9LfnIniDXE3U+ahBf4m3TJltYFBGbiiTR/xqMtJyVHOpuLDtAw==} + '@tiptap/extension-link@2.11.2': + resolution: {integrity: sha512-Mbre+JotLMUg9jdWWrwIReiRVMkA2kMzmtD2Aqy/n5P+wuI84898qIZSkhPEzDOGzp0mluUO/iGsz0NdTto/JQ==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-list-item@2.10.3': - resolution: {integrity: sha512-9sok81gvZfSta2K1Dwrq5/HSz1jk4zHBpFqCx0oydzodGslx6X1bNxdca+eXJpXZmQIWALK7zEr4X8kg3WZsgw==} + '@tiptap/extension-list-item@2.11.2': + resolution: {integrity: sha512-cxysDCvw45bem53qLZtTCkle1pttO4Y/FGqYm1hl66ol3cZsuLbjpOb4aDB6wRhyd701Ws6MjOYM+cZsmtTNpw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-ordered-list@2.10.3': - resolution: {integrity: sha512-/SFuEDnbJxy3jvi72LeyiPHWkV+uFc0LUHTUHSh20vwyy+tLrzncJfXohGbTIv5YxYhzExQYZDRD4VbSghKdlw==} + '@tiptap/extension-ordered-list@2.11.2': + resolution: {integrity: sha512-TR8OqwKkQ0OCp40V9hcRJUcO1PSzCYWXy0mvW351lOYO8D6uE+1ouVkEV9qjXBC30sVCnQykSp/FR9UjsIuiVw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-paragraph@2.10.3': - resolution: {integrity: sha512-sNkTX/iN+YoleDiTJsrWSBw9D7c4vsYwnW5y/G5ydfuJMIRQMF78pWSIWZFDRNOMkgK5UHkhu9anrbCFYgBfaA==} + '@tiptap/extension-paragraph@2.11.2': + resolution: {integrity: sha512-iydTjeZbPJuqctOaAx7QebLPvz9J/hBxPptuhe4GZmqInknAk7+SFJagYeGNb14wfXKOvDZ9DMqv6mBiqSA90Q==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-strike@2.10.3': - resolution: {integrity: sha512-jYoPy6F6njYp3txF3u23bgdRy/S5ATcWDO9LPZLHSeikwQfJ47nqb+EUNo5M8jIOgFBTn4MEbhuZ6OGyhnxopA==} + '@tiptap/extension-strike@2.11.2': + resolution: {integrity: sha512-n/rznmhqFlENGSlFY9t3pWnWzSmvDpUj3sjVhdpYteis+OCzabN9+c5KdQTBPMjtwRuRleQiKWnHmxvif0heEg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table-cell@2.10.3': - resolution: {integrity: sha512-EYzBrnq7KUAcRhshIoTmC4ED8YoF4Ei5m8ZMPOctKX+QMAagKdcrw2UxuOf4tP2xgBYx+qDsKCautepZXQiL2g==} + '@tiptap/extension-table-cell@2.11.2': + resolution: {integrity: sha512-m//QPQ/GN4mMuj2/PcT2HmUGF3bFk41zN3hDcOmfrszClsmcEVIViApVr7U6HqlIq4TFAFDLXtIK79FW9ByIDg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table-header@2.10.3': - resolution: {integrity: sha512-zJqzivz+VITYIFXNH09leBbkwAPuvp504rCAFL2PMa1uaME6+oiiRqZvXQrOiRkjNpOWEXH4dqvVLwkSMZoWaw==} + '@tiptap/extension-table-header@2.11.2': + resolution: {integrity: sha512-y2MCki8jZWT/cM4eG/3sPwUvtsj5d/+7RibbhjWnz1u42XyPoHKTZr9ZqUOAJ67vwB8LF8n8qb7D1YDqvDyA9Q==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table-row@2.10.3': - resolution: {integrity: sha512-l6P6BAE4SuIFdPmsRd+zGP2Ks9AhLAua7nfDlHFMWDnfOeaJu7g/t4oG++9xTojDcVDHhcIe8TJYUXfhOt2anw==} + '@tiptap/extension-table-row@2.11.2': + resolution: {integrity: sha512-8eCWoaijS6JD0gJOsqg8BhcTNW6I1uvq6JwnAnpv3lznHj19Q5mevC7ixuFRe9Wk/qiYZaCBXk6NcpzaqB8o/g==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-table@2.10.3': - resolution: {integrity: sha512-XAvq0ptpHfuN7lQhTeew4Sqo8aKYHTqroa7cHL8I+gWJqYqKJSTGb4FAqdGIFEzHvnSsMCFbTL//kAHXvTdsHg==} + '@tiptap/extension-table@2.11.2': + resolution: {integrity: sha512-s3pVORRDrm1AHuENhvuONpI4KtLLGJbg8QLxO/a7qeScAjHR0V9lOqdpweNfPgiMwj5zMV45tGF/tweM4x2fJQ==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-task-item@2.10.3': - resolution: {integrity: sha512-vE4qxGrZTdwynHq6l5xN0jI0ahDZpmKeoD6yuCMNyN831dgHXEjNrV8oBtZUvvqChFRc/LiSmUbrTInUn5xeNg==} + '@tiptap/extension-task-item@2.11.2': + resolution: {integrity: sha512-TvEfOq81lg7QcaP6VLolSEFQVoop4v0PxWZuzmtpOSywrdelPtLE0PuStfu0FIJIrw1V7axEwoapPCaVwTM8Mg==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 - '@tiptap/extension-task-list@2.10.3': - resolution: {integrity: sha512-Zj1pj+6VrL8VXlFYWdcLlCMykzARsvdqdU8cGVnBuC0H0vrSSfLGl+GxGnQwxTnqiNtxR4t70DLi/UjFBvzlqw==} + '@tiptap/extension-task-list@2.11.2': + resolution: {integrity: sha512-Wy4EYZQJqt/Z6oTlZ+RvaPrDivkyyVuca5cOwcGavrFsUtqvEv/QKxvAl59fsRgofYW6QsfK72K2GpppBBlVUw==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-text-align@2.10.3': - resolution: {integrity: sha512-g75sNl73gtgjP3XIcl06kvv1qw3c0rGEUD848rUU1bvlBpU3IxjkcQLgYvHmv3vpuUp9cKUkA2wa7Sv6R3fjvw==} + '@tiptap/extension-text-align@2.11.2': + resolution: {integrity: sha512-0QfjepmK+iHubjTsJshuhSZvF54M+vaqpReDraf9NKVx+WkiZ+mxJX4S5nZwoFsp21sEz7Q7z03+uXgb/yj7mQ==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-text-style@2.10.3': - resolution: {integrity: sha512-TalYIdlF7vBA4afFhmido7AORdBbu3sV+HCByda0FiNbM6cjng3Nr9oxHOCVJy+ChqrcgF4m54zDfLmamdyu5Q==} + '@tiptap/extension-text-style@2.11.2': + resolution: {integrity: sha512-RAa7BTwEOJRZN3EB2lg03KXyu7JC/Ce96cerh3D0Fo78yrtKOArPaiVHoTki6ZEIG43ccHEit1PPjMYxivPPeg==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-text@2.10.3': - resolution: {integrity: sha512-7p9XiRprsRZm8y9jvF/sS929FCELJ5N9FQnbzikOiyGNUx5mdI+exVZlfvBr9xOD5s7fBLg6jj9Vs0fXPNRkPg==} + '@tiptap/extension-text@2.11.2': + resolution: {integrity: sha512-fJZeKYM5jeJ7NpS3FWLnC/NAvg+mZNbcTaRgXMo5ljBCgiMcYHhYg9p/RHk4SeICZBBpR9WSSZXHMACd9CbJiA==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/extension-underline@2.10.3': - resolution: {integrity: sha512-VeGs0jeNiTnXddHHJEgOc/sKljZiyTEgSSuqMmsBACrr9aGFXbLTgKTvNjkZ9WzSnu7LwgJuBrwEhg8yYixUyQ==} + '@tiptap/extension-underline@2.11.2': + resolution: {integrity: sha512-Gq7hfV3D/3E1zoE6JXSYZ3boKfbjebFu7IuQZ6w6QSS/IkGN8c6kW+WtkhOKN3jV7Z5uF5KIVp3XCqNIwChWNQ==} peerDependencies: '@tiptap/core': ^2.7.0 - '@tiptap/pm@2.10.3': - resolution: {integrity: sha512-771p53aU0KFvujvKpngvq2uAxThlEsjYaXcVVmwrhf0vxSSg+psKQEvqvWvHv/3BwkPVCGwmEKNVJZjaXFKu4g==} + '@tiptap/pm@2.11.2': + resolution: {integrity: sha512-lNOMFRcD0mGy7Hf8tFMHW/fnglvq3dA0grs0QrSY4cHyYbH9BHtQjLMDceczXdXbXZq7nEqC40UBWNnqtaclpw==} - '@tiptap/react@2.10.3': - resolution: {integrity: sha512-5GBL3arWai8WZuCl1MMA7bT5aWwqDi5AOQhX+hovKjwHvttpKDogRoUBL5k6Eds/eQMBMGTpsfmZlGNiFxSv1g==} + '@tiptap/react@2.11.2': + resolution: {integrity: sha512-fhrfgXQwyc34L6ju+zzNGMa6J94+W20yww0BHyrqojUzjpYskVdO7/37h4OBfFGEhrAhLEXXDxRZcrNPtBf86A==} peerDependencies: '@tiptap/core': ^2.7.0 '@tiptap/pm': ^2.7.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tiptap/starter-kit@2.10.3': - resolution: {integrity: sha512-oq8xdVIMqohSs91ofHSr7i5dCp2F56Lb9aYIAI25lZmwNwQJL2geGOYjMSfL0IC4cQHPylIuSKYCg7vRFdZmAA==} + '@tiptap/starter-kit@2.11.2': + resolution: {integrity: sha512-FUIblP9BSmBzskf/aX7AIcUK5XP5Gi/VqUqm5evCkzlR1FrggLoy+vY+CX0me4oE/WYk4KAgIRXkE9tcbwotQA==} '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} - '@trpc/client@11.0.0-rc.660': - resolution: {integrity: sha512-bNpkZEfyMGKHynYFxdLpY8nJ1n7E3JHKcd4Pe2cagmpkzOEF9tFT3kzNf+eLI8XMG8196lTRR0J0W2/1Q8/cug==} + '@trpc/client@11.0.0-rc.700': + resolution: {integrity: sha512-8yktSkK/jbDss4pA+3EwwDY972qBrvGN49Kpa7oA/0My40YohlEwrEwLLI5+rdICUi3MFv7jkqzKydgXHJJPRw==} peerDependencies: - '@trpc/server': 11.0.0-rc.660+74625d5e4 - typescript: '>=5.6.2' + '@trpc/server': 11.0.0-rc.700+e5c0c1a82 + typescript: '>=5.7.2' - '@trpc/next@11.0.0-rc.660': - resolution: {integrity: sha512-LQHdiVED8h+CJEAy/X9PDmY3fM8VPdZ+3bVkbmEiP4xoNnSKRTbSbknFyRzG9M2AogfIafF4zAZVwOvCxexyGw==} + '@trpc/next@11.0.0-rc.700': + resolution: {integrity: sha512-IZoDhq577LDUZ22S9XO7PJzlh0erWnuuaoExYXGz3UV/5HhQ91c3+hSGvx8s7BiOAWdMeFDGxanwjaUMaJquXg==} peerDependencies: '@tanstack/react-query': ^5.59.15 - '@trpc/client': 11.0.0-rc.660+74625d5e4 - '@trpc/react-query': 11.0.0-rc.660+74625d5e4 - '@trpc/server': 11.0.0-rc.660+74625d5e4 + '@trpc/client': 11.0.0-rc.700+e5c0c1a82 + '@trpc/react-query': 11.0.0-rc.700+e5c0c1a82 + '@trpc/server': 11.0.0-rc.700+e5c0c1a82 next: '*' react: '>=16.8.0' react-dom: '>=16.8.0' - typescript: '>=5.6.2' + typescript: '>=5.7.2' peerDependenciesMeta: '@tanstack/react-query': optional: true '@trpc/react-query': optional: true - '@trpc/react-query@11.0.0-rc.660': - resolution: {integrity: sha512-U2BHtYVt+8jt0a8Nrrk5cep8O1UZRxtTCBHtXie9kmJyQWWml43KfHxL5ssnFywaFrDZQz6Ec7kIoOxR/CQNfg==} + '@trpc/react-query@11.0.0-rc.700': + resolution: {integrity: sha512-/8tZ7PrfVFOKHjtekSCE0smJLO6v2xxuaXbnSDV7saCoJXIID/+olt3YbwvhAzEzFCaWF9UUuigULW4MIr9Hvw==} peerDependencies: - '@tanstack/react-query': ^5.59.15 - '@trpc/client': 11.0.0-rc.660+74625d5e4 - '@trpc/server': 11.0.0-rc.660+74625d5e4 + '@tanstack/react-query': ^5.62.8 + '@trpc/client': 11.0.0-rc.700+e5c0c1a82 + '@trpc/server': 11.0.0-rc.700+e5c0c1a82 react: '>=18.2.0' react-dom: '>=18.2.0' - typescript: '>=5.6.2' + typescript: '>=5.7.2' - '@trpc/server@11.0.0-rc.660': - resolution: {integrity: sha512-QUapcZCNOpHT7ng9LceGc9ImkboWd0Go9ryrduZpL+p4jdfaC6409AQ3x4XEW6Wu3yBmZAn4CywCsDrDhjDy/w==} + '@trpc/server@11.0.0-rc.700': + resolution: {integrity: sha512-EmbaGj76YcZWsnujZrrJEYa/2a6ZncTMm1he99RlemWE/ZsZbN+I+KCz+VKIsUr+JLaQmQMElcXs2x0qLI6T5g==} peerDependencies: - typescript: '>=5.6.2' + typescript: '>=5.7.2' '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -3690,9 +4204,15 @@ packages: resolution: {integrity: sha512-PSys7Hy5NuX76HBleOkd8wlRtI4GCzLHS2XUpKeGIj0vpzH4fqE+tpi7fBb5t9U7UiyM6E6pyabSKjoD2zUsoQ==} hasBin: true + '@types/adm-zip@0.5.7': + resolution: {integrity: sha512-DNEs/QvmyRLurdQPChqq0Md4zGvPwHerAJYWk9l2jCbD1VPpnzRJorOdiq4zsw09NFbYnhfsoEhWtxIzXpn2yw==} + '@types/asn1@0.2.4': resolution: {integrity: sha512-V91DSJ2l0h0gRhVP4oBfBzRBN9lAbPUkGDMCnwedqPKX2d84aAMc9CulOvxdw1f7DfEYx99afab+Rsm3e52jhA==} + '@types/aws-lambda@8.10.146': + resolution: {integrity: sha512-3BaDXYTh0e6UCJYL/jwV/3+GRslSc08toAiZSmleYtkAUyV5rtvdPYxrG/88uqvTuT6sb27WE9OS90ZNTIuQ0g==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -3714,8 +4234,8 @@ packages: '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} - '@types/chroma-js@2.4.4': - resolution: {integrity: sha512-/DTccpHTaKomqussrn+ciEvfW4k6NAHzNzs/sts1TCqg333qNxOhy8TNIoQCmbGG3Tl8KdEhkGAssb1n3mTXiQ==} + '@types/chroma-js@3.1.0': + resolution: {integrity: sha512-Uwl3SOtUkbQ6Ye6ZYu4q4xdLGBzmY839sEHYtOT7i691neeyd+7fXWT5VIkcUSfNwIFrIjQutNYQn9h4q5HFvg==} '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} @@ -3741,8 +4261,8 @@ packages: '@types/docker-modem@3.0.6': resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} - '@types/dockerode@3.3.32': - resolution: {integrity: sha512-xxcG0g5AWKtNyh7I7wswLdFvym4Mlqks5ZlKzxEUrGHS0r0PUOfxm2T0mspwu10mHQqu3Ck3MI3V2HqvLWE1fg==} + '@types/dockerode@3.3.34': + resolution: {integrity: sha512-mH9SuIb8NuTDsMus5epcbTzSbEo52fKLBMo0zapzYIAIyfDqoIFn7L3trekHLKC8qmxGV++pPUP4YqQ9n5v2Zg==} '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -3798,15 +4318,15 @@ packages: '@types/node@18.19.50': resolution: {integrity: sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==} - '@types/node@22.10.2': - resolution: {integrity: sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==} + '@types/node@22.10.7': + resolution: {integrity: sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==} + + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} '@types/prismjs@1.26.5': resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} - '@types/prop-types@15.7.12': - resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} - '@types/qs@6.9.16': resolution: {integrity: sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==} @@ -3816,16 +4336,16 @@ packages: '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/react-dom@19.0.2': - resolution: {integrity: sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==} + '@types/react-dom@19.0.3': + resolution: {integrity: sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA==} peerDependencies: '@types/react': ^19.0.0 - '@types/react@18.3.13': - resolution: {integrity: sha512-ii/gswMmOievxAJed4PAHT949bpYjPKXvXo1v6cRB/kqc2ZR4n+SgyCyvyc5Fec5ez8VnUumI1Vk7j6fRyRogg==} + '@types/react@19.0.7': + resolution: {integrity: sha512-MoFsEJKkAtZCrC1r6CM8U22GzhG7u2Wir8ons/aCKH6MBdD1ibV24zOSSkdZVUKqN5i396zG5VKLYZ3yaUZdLA==} - '@types/react@19.0.1': - resolution: {integrity: sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==} + '@types/semver@7.5.8': + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} '@types/send@0.17.4': resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} @@ -3872,51 +4392,51 @@ packages: '@types/xml2js@0.4.14': resolution: {integrity: sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==} - '@typescript-eslint/eslint-plugin@8.18.0': - resolution: {integrity: sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==} + '@typescript-eslint/eslint-plugin@8.20.0': + resolution: {integrity: sha512-naduuphVw5StFfqp4Gq4WhIBE2gN1GEmMUExpJYknZJdRnc+2gDzB8Z3+5+/Kv33hPQRDGzQO/0opHE72lZZ6A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/parser@8.18.0': - resolution: {integrity: sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==} + '@typescript-eslint/parser@8.20.0': + resolution: {integrity: sha512-gKXG7A5HMyjDIedBi6bUrDcun8GIjnI8qOwVLiY3rx6T/sHP/19XLJOnIq/FgQvWLHja5JN/LSE7eklNBr612g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/scope-manager@8.18.0': - resolution: {integrity: sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==} + '@typescript-eslint/scope-manager@8.20.0': + resolution: {integrity: sha512-J7+VkpeGzhOt3FeG1+SzhiMj9NzGD/M6KoGn9f4dbz3YzK9hvbhVTmLj/HiTp9DazIzJ8B4XcM80LrR9Dm1rJw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.18.0': - resolution: {integrity: sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==} + '@typescript-eslint/type-utils@8.20.0': + resolution: {integrity: sha512-bPC+j71GGvA7rVNAHAtOjbVXbLN5PkwqMvy1cwGeaxUoRQXVuKCebRoLzm+IPW/NtFFpstn1ummSIasD5t60GA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/types@8.18.0': - resolution: {integrity: sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==} + '@typescript-eslint/types@8.20.0': + resolution: {integrity: sha512-cqaMiY72CkP+2xZRrFt3ExRBu0WmVitN/rYPZErA80mHjHx/Svgp8yfbzkJmDoQ/whcytOPO9/IZXnOc+wigRA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.18.0': - resolution: {integrity: sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==} + '@typescript-eslint/typescript-estree@8.20.0': + resolution: {integrity: sha512-Y7ncuy78bJqHI35NwzWol8E0X7XkRVS4K4P4TCyzWkOJih5NDvtoRDW4Ba9YJJoB2igm9yXDdYI/+fkiiAxPzA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/utils@8.18.0': - resolution: {integrity: sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==} + '@typescript-eslint/utils@8.20.0': + resolution: {integrity: sha512-dq70RUw6UK9ei7vxc4KQtBRk7qkHZv447OUZ6RPQMQl71I3NZxQJX/f32Smr+iqWrB02pHKn2yAdHBb0KNrRMA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/visitor-keys@8.18.0': - resolution: {integrity: sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==} + '@typescript-eslint/visitor-keys@8.20.0': + resolution: {integrity: sha512-v/BpkeeYAsPkKCkR8BDwcno0llhzWVqPOamQrAEMdpZav2Y9OVjd9dwJyBLJWwf335B5DmlifECIkZRJCaGaHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@umami/node@0.4.0': @@ -4089,6 +4609,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + adm-zip@0.5.16: + resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} + engines: {node: '>=12.0'} + aes-decrypter@4.0.2: resolution: {integrity: sha512-lc+/9s6iJvuaRe5qDlMTpCFjnwpkeOXp8qP3oiZ5jsj1MRg+SBVUmmICrhxHvc8OELSmc+fEyyxAuppY6hrWzw==} @@ -4100,10 +4624,18 @@ packages: resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} engines: {node: '>= 14'} + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} + aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} + aggregate-error@5.0.0: + resolution: {integrity: sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==} + engines: {node: '>=18'} + ajv-keywords@3.5.2: resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} peerDependencies: @@ -4119,6 +4651,10 @@ packages: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -4139,6 +4675,9 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + apg-lite@1.0.4: resolution: {integrity: sha512-B32zCN3IdHIc99Vy7V9BaYTUzLeRA8YXYY1aQD1/5I2aqIrO0coi4t6hJPqMisidlBxhyME8UexkHt31SlR6Og==} @@ -4167,6 +4706,9 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + argv-formatter@1.0.0: + resolution: {integrity: sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==} + aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -4175,6 +4717,13 @@ packages: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-ify@1.0.0: + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + array-includes@3.1.8: resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} @@ -4199,6 +4748,10 @@ packages: resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} engines: {node: '>= 0.4'} + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + array.prototype.tosorted@1.1.4: resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} engines: {node: '>= 0.4'} @@ -4207,6 +4760,10 @@ packages: resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} engines: {node: '>= 0.4'} + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + asn1@0.2.6: resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} @@ -4306,12 +4863,15 @@ packages: resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==} engines: {node: '>= 10.0.0'} + before-after-hook@3.0.2: + resolution: {integrity: sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==} + bellajs@11.2.0: resolution: {integrity: sha512-Wjss+Bc674ZABPr+SCKWTqA4V1pyYFhzDTjNBJy4jdmgOv0oGIGXeKBRJyINwP5tIy+iIZD9SfgZpztduzQ5QA==} engines: {node: '>= 18.4'} - better-sqlite3@11.7.0: - resolution: {integrity: sha512-mXpa5jnIKKHeoGzBrUJrc65cXFKcILGZpU3FXR0pradUEm9MA7UZz02qfEejaMcm9iXrSOCenwwYMJ/tZ1y5Ig==} + better-sqlite3@11.8.0: + resolution: {integrity: sha512-aKv9s2dir7bsEX5RIjL9HHWB9uQ+f6Vch5B4qmeAOop4Y9OYHX+PNKLr+mpv6+d8L/ZYh4l7H8zPuVMbWkVMLw==} big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -4322,6 +4882,9 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + bottleneck@2.19.5: + resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} + boxen@5.1.2: resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} engines: {node: '>=10'} @@ -4374,10 +4937,22 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -4412,9 +4987,17 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + change-case@3.1.0: resolution: {integrity: sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==} + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + character-entities-legacy@1.1.4: resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} @@ -4463,6 +5046,10 @@ packages: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} + clean-stack@5.2.0: + resolution: {integrity: sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==} + engines: {node: '>=14.16'} + cli-boxes@2.2.1: resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} engines: {node: '>=6'} @@ -4475,10 +5062,19 @@ packages: resolution: {integrity: sha512-q/CIxOggmzAw/67QYS4j1bMo72IpC+dAlswZl8xHxp8XvmWS97x3Q30pWNXq8mg0pZLSJwIFWZpUWTfcF119wA==} hasBin: true + cli-highlight@2.1.11: + resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + cli-width@3.0.0: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} engines: {node: '>= 10'} @@ -4486,6 +5082,9 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -4529,6 +5128,10 @@ packages: color@3.2.1: resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + colorspace@1.1.4: resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} @@ -4546,6 +5149,9 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + compare-func@2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + compress-commons@6.0.2: resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} engines: {node: '>= 14'} @@ -4553,8 +5159,8 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - concurrently@9.1.0: - resolution: {integrity: sha512-VxkzwMAn4LP7WyMnJNbHN5mKV9L2IbyDjpzemKr99sXNR3GqRNMMHdm7prV1ws9wg7ETj6WUkNOigZVsptwbgg==} + concurrently@9.1.2: + resolution: {integrity: sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==} engines: {node: '>=18'} hasBin: true @@ -4575,6 +5181,32 @@ packages: constant-case@2.0.0: resolution: {integrity: sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==} + conventional-changelog-angular@8.0.0: + resolution: {integrity: sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==} + engines: {node: '>=18'} + + conventional-changelog-conventionalcommits@8.0.0: + resolution: {integrity: sha512-eOvlTO6OcySPyyyk8pKz2dP4jjElYunj9hn9/s0OB+gapTO8zwS9UQWrZ1pmF2hFs3vw1xhonOLGcGjy/zgsuA==} + engines: {node: '>=18'} + + conventional-changelog-writer@8.0.0: + resolution: {integrity: sha512-TQcoYGRatlAnT2qEWDON/XSfnVG38JzA7E0wcGScu7RElQBkg9WWgZd1peCWFcWDh1xfb2CfsrcvOn1bbSzztA==} + engines: {node: '>=18'} + hasBin: true + + conventional-commits-filter@5.0.0: + resolution: {integrity: sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==} + engines: {node: '>=18'} + + conventional-commits-parser@6.0.0: + resolution: {integrity: sha512-TbsINLp48XeMXR8EvGjTnKGsZqBemisPoyWESlpRyR8lif0lcwzqz+NMtYSj1ooF/WYjSuu7wX0CtdeeMEQAmA==} + engines: {node: '>=18'} + hasBin: true + + convert-hrtime@5.0.0: + resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==} + engines: {node: '>=12'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -4589,8 +5221,8 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} - cookie@1.0.1: - resolution: {integrity: sha512-Xd8lFX4LM9QEEwxQpF9J9NTUh8pmdJO0cyRJhFiDoLTk2eH8FXlRv2IFGYVadZpqI3j8fhNrSdKCeYPxiAhLXw==} + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} cookies@0.9.1: @@ -4614,6 +5246,15 @@ packages: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} + cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + cpu-features@0.0.10: resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==} engines: {node: '>=10.0.0'} @@ -4656,6 +5297,10 @@ packages: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} + crypto-random-string@4.0.0: + resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} + engines: {node: '>=12'} + css.escape@1.5.1: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} @@ -4664,8 +5309,8 @@ packages: engines: {node: '>=4'} hasBin: true - cssstyle@4.1.0: - resolution: {integrity: sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==} + cssstyle@4.2.1: + resolution: {integrity: sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==} engines: {node: '>=18'} csstype@3.1.3: @@ -4686,14 +5331,26 @@ packages: resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} engines: {node: '>= 0.4'} + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + data-view-byte-length@1.0.1: resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} engines: {node: '>= 0.4'} + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + data-view-byte-offset@1.0.0: resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} engines: {node: '>= 0.4'} + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} @@ -4714,6 +5371,15 @@ packages: supports-color: optional: true + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} @@ -4820,8 +5486,8 @@ packages: resolution: {integrity: sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ==} engines: {node: '>= 8.0'} - docker-modem@5.0.3: - resolution: {integrity: sha512-89zhop5YVhcPEt5FpUFGr3cDyceGhq/F9J+ZndQ4KfqNvfbJpPMfgeixFgUj5OjCYAboElqODxY5Z1EBsSa6sg==} + docker-modem@5.0.5: + resolution: {integrity: sha512-Cxw8uEcvNTRmsQuGqzzfiCnfGgf96tVJItLh8taOX0miTcIBALKH5TckCSuZbpbjP7uhAl81dOL9sxfa6HgCIg==} engines: {node: '>= 8.0'} dockerode@3.3.5: @@ -4852,8 +5518,8 @@ packages: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} - dotenv-cli@7.4.4: - resolution: {integrity: sha512-XkBYCG0tPIes+YZr4SpfFv76SQrV/LeCE8CI7JSEMi3VR9MvTihCGTOtbIexD6i2mXF+6px7trb1imVCXSNMDw==} + dotenv-cli@8.0.0: + resolution: {integrity: sha512-aLqYbK7xKOiTMIRf1lDPbI+Y+Ip/wo5k3eyp6ePysVaSqbyxjyK3dK35BTxG+rmd7djf5q2UPs4noPNH+cj0Qw==} hasBin: true dotenv-expand@10.0.0: @@ -4872,12 +5538,12 @@ packages: resolution: {integrity: sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==} engines: {node: '>=4'} - drizzle-kit@0.30.1: - resolution: {integrity: sha512-HmA/NeewvHywhJ2ENXD3KvOuM/+K2dGLJfxVfIHsGwaqKICJnS+Ke2L6UcSrSrtMJLJaT0Im1Qv4TFXfaZShyw==} + drizzle-kit@0.30.2: + resolution: {integrity: sha512-vhdLrxWA32WNVF77NabpSnX7pQBornx64VDQDmKddRonOB2Xe/yY4glQ7rECoa+ogqcQNo7VblLUbeBK6Zn9Ow==} hasBin: true - drizzle-orm@0.38.1: - resolution: {integrity: sha512-TpOzNrPGy7dl0/uP9vKD6ATzp9noJaRYhOYqtOCKxxwSmZqrPxN4SW5kWawVUIcbSd2lkbDCdZue+gtVNLmQsg==} + drizzle-orm@0.38.4: + resolution: {integrity: sha512-s7/5BpLKO+WJRHspvpqTydxFob8i1vo2rEx4pY6TGY7QSMuUfWUuzaY0DIpXCkgHOo37BaFC+SJQb99dDUXT3Q==} peerDependencies: '@aws-sdk/client-rds-data': '>=3' '@cloudflare/workers-types': '>=4' @@ -4968,12 +5634,19 @@ packages: sqlite3: optional: true - drizzle-zod@0.6.0: - resolution: {integrity: sha512-7K1k7Y/5Jw9D4cTlrHL3mRTLg3oaglbi4VvBIYmSAtMvYkgqvusPtra7cnntMCe1r1cBcwxhlEkfiNdU23lp2g==} + drizzle-zod@0.6.1: + resolution: {integrity: sha512-huEbUgnsuR8tupnmLiyB2F1I2H9dswI3GfM36IbIqx9i0YUeYjRsDpJVyFVeziUvI1ogT9JHRL2Q03cC4QmvxA==} peerDependencies: drizzle-orm: '>=0.36.0' zod: '>=3.0.0' + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -4989,6 +5662,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + emojilib@2.4.0: + resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} + emojis-list@3.0.0: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} engines: {node: '>= 4'} @@ -5018,20 +5694,43 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + env-ci@11.1.0: + resolution: {integrity: sha512-Z8dnwSDbV1XYM9SBF2J0GcNVvmfmfh3a49qddGIROhBoVro6MZVTji15z/sJbQ2ko2ei8n988EU1wzoLU/tF+g==} + engines: {node: ^18.17 || >=20.6.1} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + es-abstract@1.23.3: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} + es-abstract@1.23.7: + resolution: {integrity: sha512-OygGC8kIcDhXX+6yAZRGLqwi2CmEXCbLQixeGUgYeR+Qwlppqmo7DIDr8XibtEBZp+fJcoYpoatp5qwLMEdcqQ==} + engines: {node: '>= 0.4'} + es-define-property@1.0.0: resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} engines: {node: '>= 0.4'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-iterator-helpers@1.1.0: - resolution: {integrity: sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==} + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} es-module-lexer@1.5.4: @@ -5052,6 +5751,10 @@ packages: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + esbuild-register@3.6.0: resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} peerDependencies: @@ -5098,13 +5801,17 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + escodegen@2.1.0: resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} engines: {node: '>=6.0'} hasBin: true - eslint-config-prettier@9.1.0: - resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + eslint-config-prettier@10.0.1: + resolution: {integrity: sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==} hasBin: true peerDependencies: eslint: '>=7.0.0' @@ -5160,8 +5867,8 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - eslint-plugin-react@7.37.2: - resolution: {integrity: sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==} + eslint-plugin-react@7.37.4: + resolution: {integrity: sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 @@ -5187,8 +5894,8 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.16.0: - resolution: {integrity: sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==} + eslint@9.18.0: + resolution: {integrity: sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -5244,6 +5951,14 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + execa@9.5.2: + resolution: {integrity: sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==} + engines: {node: ^18.19.0 || >=20.5.0} + expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} @@ -5256,12 +5971,19 @@ packages: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} + fast-content-type-parse@2.0.1: + resolution: {integrity: sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} fast-fifo@1.3.2: resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -5311,10 +6033,18 @@ packages: fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + figures@2.0.0: + resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==} + engines: {node: '>=4'} + figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -5326,12 +6056,24 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + find-up-simple@1.0.0: + resolution: {integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==} + engines: {node: '>=18'} + + find-up@2.1.0: + resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} + engines: {node: '>=4'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flag-icons@7.2.3: - resolution: {integrity: sha512-X2gUdteNuqdNqob2KKTJTS+ZCvyWeLCtDz9Ty8uJP17Y4o82Y+U/Vd4JNrdwTAjagYsRznOn9DZ+E/Q52qbmqg==} + find-versions@6.0.0: + resolution: {integrity: sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==} + engines: {node: '>=18'} + + flag-icons@7.3.1: + resolution: {integrity: sha512-X6tcDMgDXjSN2Xx9NwYUG3D1BGdjw0DXsM6Fjkm37ed3L/ffMtoMzQmaWUxJUYXtaqK00xMIcioA8AjfhvH71A==} flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} @@ -5363,10 +6105,17 @@ packages: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} + from2@2.3.0: + resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -5398,10 +6147,18 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function-timeout@1.0.2: + resolution: {integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==} + engines: {node: '>=18'} + function.prototype.name@1.1.6: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} @@ -5425,6 +6182,10 @@ packages: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} + get-intrinsic@1.2.6: + resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} + engines: {node: '>= 0.4'} + get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} @@ -5441,10 +6202,26 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + get-stream@7.0.1: + resolution: {integrity: sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==} + engines: {node: '>=16'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + get-symbol-description@1.0.2: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + get-tsconfig@4.8.1: resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} @@ -5455,6 +6232,9 @@ packages: git-hooks-list@3.1.0: resolution: {integrity: sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==} + git-log-parser@1.2.1: + resolution: {integrity: sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==} + github-from-package@0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} @@ -5469,17 +6249,12 @@ packages: glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.3.10: - resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true - glob@11.0.0: - resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} + glob@11.0.1: + resolution: {integrity: sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==} engines: {node: 20 || >=22} hasBin: true @@ -5510,12 +6285,20 @@ packages: resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} engines: {node: '>=8'} + globby@14.0.2: + resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==} + engines: {node: '>=18'} + globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} @@ -5555,10 +6338,18 @@ packages: resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} engines: {node: '>= 0.4'} + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} @@ -5596,6 +6387,18 @@ packages: resolution: {integrity: sha512-6NGwvttY1+HAFii08VYiEKI6ETPAFbpLntpm2M/MogEsAFWdZV74UNT+2M4bmqX90cIQhjlpBSP+tO+CfB0uww==} engines: {node: '>=16.0.0'} + hook-std@3.0.0: + resolution: {integrity: sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + hosted-git-info@7.0.2: + resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} + engines: {node: ^16.14.0 || >=18.0.0} + + hosted-git-info@8.0.2: + resolution: {integrity: sha512-sYKnA7eGln5ov8T8gnYlkSOxFJvywzEx9BueN6xo/GKO8PGiI6uK6xx+DIGe45T3bdVjLAQDQW1aicT8z8JwQg==} + engines: {node: ^18.17.0 || >=20.5.0} + html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} @@ -5622,10 +6425,22 @@ packages: resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} engines: {node: '>= 14'} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + human-signals@8.0.0: + resolution: {integrity: sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==} + engines: {node: '>=18.18.0'} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -5652,10 +6467,17 @@ packages: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} + import-from-esm@2.0.0: + resolution: {integrity: sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g==} + engines: {node: '>=18.20'} + import-lazy@2.1.0: resolution: {integrity: sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==} engines: {node: '>=4'} + import-meta-resolve@4.1.0: + resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -5664,6 +6486,14 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + + index-to-position@0.1.2: + resolution: {integrity: sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==} + engines: {node: '>=18'} + inflation@2.1.0: resolution: {integrity: sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==} engines: {node: '>= 0.8.0'} @@ -5694,14 +6524,22 @@ packages: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + intl-messageformat@10.7.1: resolution: {integrity: sha512-xQuJW2WcyzNJZWUu5xTVPOmNSA1Sowuu/NKFdUid5Fxx/Yl6/s4DefTU/y7zy+irZLDmFGmTLtnM8FqpN05wlA==} + into-stream@7.0.0: + resolution: {integrity: sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==} + engines: {node: '>=12'} + invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - ioredis@5.4.1: - resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==} + ioredis@5.4.2: + resolution: {integrity: sha512-0SZXGNGZ+WzISQ67QDyZ2x0+wVxjjUndtD8oSeik/4ajifeiRufed8fCb8QW8VMyi4MXcS+UO1k/0NGhvq1PAg==} engines: {node: '>=12.22.0'} ip-address@9.0.5: @@ -5721,6 +6559,13 @@ packages: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-arrayish@0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} @@ -5731,10 +6576,18 @@ packages: is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + is-boolean-object@1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} + is-boolean-object@1.2.1: + resolution: {integrity: sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==} + engines: {node: '>= 0.4'} + is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -5751,10 +6604,18 @@ packages: resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} engines: {node: '>= 0.4'} + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + is-decimal@1.0.4: resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} @@ -5762,8 +6623,9 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-finalizationregistry@1.0.2: - resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} @@ -5810,6 +6672,10 @@ packages: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -5840,6 +6706,10 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + is-set@2.0.3: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} @@ -5848,22 +6718,46 @@ packages: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + is-symbol@1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + is-typed-array@1.1.13: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -5871,6 +6765,10 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-upper-case@1.1.2: resolution: {integrity: sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==} @@ -5881,6 +6779,10 @@ packages: is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + is-weakref@1.1.0: + resolution: {integrity: sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==} + engines: {node: '>= 0.4'} + is-weakset@2.0.3: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} @@ -5908,6 +6810,10 @@ packages: isomorphic-fetch@3.0.0: resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==} + issue-parser@7.0.1: + resolution: {integrity: sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg==} + engines: {node: ^18.17 || >=20.6.1} + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -5924,14 +6830,10 @@ packages: resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} engines: {node: '>=8'} - iterator.prototype@1.1.3: - resolution: {integrity: sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==} + iterator.prototype@1.1.4: + resolution: {integrity: sha512-x4WH0BWmrMmg4oHHl+duwubhrvczGlyuGAZu3nvrf0UXOfPu8IhZObFEr7DE/iv01YgVZrsOiRcqw2srkKEDIA==} engines: {node: '>= 0.4'} - jackspeak@2.3.6: - resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} - engines: {node: '>=14'} - jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} @@ -5939,6 +6841,10 @@ packages: resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==} engines: {node: 20 || >=22} + java-properties@1.0.2: + resolution: {integrity: sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==} + engines: {node: '>= 0.6.0'} + jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} @@ -5949,8 +6855,8 @@ packages: jose@5.9.6: resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} - jotai@2.10.3: - resolution: {integrity: sha512-Nnf4IwrLhNfuz2JOQLI0V/AgwcpxvVy8Ec8PidIIDeRi4KCFpwTFIpHAAcU+yCgnw/oASYElq9UY0YdUUegsSA==} + jotai@2.11.0: + resolution: {integrity: sha512-zKfoBBD1uDw3rljwHkt0fWuja1B76R7CjznuBO+mSX6jpsO1EBeWNRKpeaQho9yPI/pvCv4recGfgOXGxwPZvQ==} engines: {node: '>=12.20.0'} peerDependencies: '@types/react': '>=17.0.0' @@ -5977,11 +6883,11 @@ packages: jsbn@1.1.0: resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - jsdom@25.0.1: - resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} + jsdom@26.0.0: + resolution: {integrity: sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==} engines: {node: '>=18'} peerDependencies: - canvas: ^2.11.2 + canvas: ^3.0.0 peerDependenciesMeta: canvas: optional: true @@ -5994,6 +6900,9 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-better-errors@1.0.2: + resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -6048,19 +6957,26 @@ packages: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} - ldapts@7.2.2: - resolution: {integrity: sha512-UotAq24/vJEz0m3w/jgwZm7JGNw8M6vexL/5KU5pe3aIZWBkT/HRhjsPw/buRqKSK5Y0vTu5Zv8iyPgQF7ozzg==} + ldapts@7.3.1: + resolution: {integrity: sha512-g8mxobOSeuxVkXRT9JZBGUvfDjXIpQPEHH5kYG9UjrIlWV5Rqxq+MMmqzlSh4OqSXh+3lFvzyYu+lsJldoZvvA==} engines: {node: '>=18'} levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} - linkifyjs@4.1.3: - resolution: {integrity: sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg==} + linkifyjs@4.2.0: + resolution: {integrity: sha512-pCj3PrQyATaoTYKHrgWRF3SJwsm61udVh+vuls/Rl6SptiDhgE7ziUIudAedRY9QEfynmM7/RmLEfPUyw1HPCw==} + + load-json-file@4.0.0: + resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} + engines: {node: '>=4'} loader-runner@4.3.0: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} @@ -6070,10 +6986,20 @@ packages: resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} engines: {node: '>=8.9.0'} + locate-path@2.0.0: + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} + engines: {node: '>=4'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + lodash.capitalize@4.2.1: + resolution: {integrity: sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==} + lodash.clonedeep@4.5.0: resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} @@ -6083,15 +7009,27 @@ packages: lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + lodash.escaperegexp@4.1.2: + resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} + lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} lodash.isarguments@3.1.0: resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.uniqby@4.7.0: + resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -6129,8 +7067,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.0.1: - resolution: {integrity: sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==} + lru-cache@11.0.2: + resolution: {integrity: sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -6164,8 +7102,8 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - mantine-react-table@2.0.0-beta.7: - resolution: {integrity: sha512-jpM3hXLL+DHURmm1AJ2uOyxu3xiZvlzS7NOtDh5qHo2AIv9zEEkXK/mrvKmRvXJ0O8pVPHLuYKAel9RBY5NfUA==} + mantine-react-table@2.0.0-beta.8: + resolution: {integrity: sha512-3Ey0jbLtqcN89n24kDRiOeYwhR5zcfHzzCz7KOip5fXvvrtn6N7vj+Fw2jYFFbPQr7TLzBviSSQkPcVyQbs+/w==} engines: {node: '>=16'} peerDependencies: '@mantine/core': ^7.9 @@ -6181,6 +7119,21 @@ packages: resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} hasBin: true + marked-terminal@7.2.1: + resolution: {integrity: sha512-rQ1MoMFXZICWNsKMiiHwP/Z+92PLKskTPXj+e7uwXmuMPkNn7iTqC+IvDekVm1MPeC9wYQeLxeFaOvudRR/XbQ==} + engines: {node: '>=16.0.0'} + peerDependencies: + marked: '>=1 <15' + + marked@12.0.2: + resolution: {integrity: sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==} + engines: {node: '>= 18'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} @@ -6188,6 +7141,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + meow@13.2.0: + resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -6212,10 +7169,19 @@ packages: engines: {node: '>=10.0.0'} hasBin: true + mime@4.0.4: + resolution: {integrity: sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ==} + engines: {node: '>=16'} + hasBin: true + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} @@ -6303,10 +7269,13 @@ packages: engines: {node: '>=8', npm: '>=5'} hasBin: true - mysql2@3.11.5: - resolution: {integrity: sha512-0XFu8rUmFN9vC0ME36iBvCUObftiMHItrYFhlCRvFWbLgpNqtC4Br/NmZX1HNCszxT0GGy5QtP+k3Q3eCJPaYA==} + mysql2@3.12.0: + resolution: {integrity: sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw==} engines: {node: '>= 8.0'} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + named-placeholders@1.1.3: resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} engines: {node: '>=12.0.0'} @@ -6345,6 +7314,9 @@ packages: resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} engines: {node: '>= 10'} + nerf-dart@1.0.0: + resolution: {integrity: sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==} + netmask@2.0.2: resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} engines: {node: '>= 0.4.0'} @@ -6365,27 +7337,30 @@ packages: nodemailer: optional: true - next-intl@3.26.1: - resolution: {integrity: sha512-TE4cQgXNw4jzEtVPdiYQOCmhAu+Z2qoUppCMxPkJoz8XXe8TdqiNEPhD/GtXEsI80nV6NnVAq3hyTHH5+ex6Hw==} + next-intl@3.26.3: + resolution: {integrity: sha512-6Y97ODrDsEE1J8cXKMHwg1laLdtkN66QMIqG8BzH4zennJRUNTtM8UMtBDyhfmF6uiZ+xsbWLXmHUgmUymUsfQ==} peerDependencies: next: ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 - next@14.2.20: - resolution: {integrity: sha512-yPvIiWsiyVYqJlSQxwmzMIReXn5HxFNq4+tlVQ812N1FbvhmE+fDpIAD7bcS2mGYQwPJ5vAsQouyme2eKsxaug==} - engines: {node: '>=18.17.0'} + next@15.1.4: + resolution: {integrity: sha512-mTaq9dwaSuwwOrcu3ebjDYObekkxRnXpuVL21zotM8qE2W0HBOdVIdg2Li9QjMEZrj73LN96LcWcz62V19FjAg==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 '@playwright/test': ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': optional: true '@playwright/test': optional: true + babel-plugin-react-compiler: + optional: true sass: optional: true @@ -6420,6 +7395,10 @@ packages: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} + node-emoji@2.2.0: + resolution: {integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==} + engines: {node: '>=18'} + node-fetch-commonjs@3.3.2: resolution: {integrity: sha512-VBlAiynj3VMLrotgwOS3OyECFxas5y7ltLcK4t41lMUZeaK15Ym4QRkqN0EQKAFL42q9i21EPKjzLUPfltR72A==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6458,20 +7437,110 @@ packages: engines: {node: '>=6'} hasBin: true + normalize-package-data@6.0.2: + resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} + engines: {node: ^16.14.0 || >=18.0.0} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + normalize-url@8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} + engines: {node: '>=14.16'} + npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} + engines: {node: '>=18'} + + npm@10.9.2: + resolution: {integrity: sha512-iriPEPIkoMYUy3F6f3wwSZAU93E0Eg6cHwIR6jzzOXWSy+SD/rOODEs74cVONHKSx2obXtuUoyidVEhISrisgQ==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + bundledDependencies: + - '@isaacs/string-locale-compare' + - '@npmcli/arborist' + - '@npmcli/config' + - '@npmcli/fs' + - '@npmcli/map-workspaces' + - '@npmcli/package-json' + - '@npmcli/promise-spawn' + - '@npmcli/redact' + - '@npmcli/run-script' + - '@sigstore/tuf' + - abbrev + - archy + - cacache + - chalk + - ci-info + - cli-columns + - fastest-levenshtein + - fs-minipass + - glob + - graceful-fs + - hosted-git-info + - ini + - init-package-json + - is-cidr + - json-parse-even-better-errors + - libnpmaccess + - libnpmdiff + - libnpmexec + - libnpmfund + - libnpmhook + - libnpmorg + - libnpmpack + - libnpmpublish + - libnpmsearch + - libnpmteam + - libnpmversion + - make-fetch-happen + - minimatch + - minipass + - minipass-pipeline + - ms + - node-gyp + - nopt + - normalize-package-data + - npm-audit-report + - npm-install-checks + - npm-package-arg + - npm-pick-manifest + - npm-profile + - npm-registry-fetch + - npm-user-validate + - p-map + - pacote + - parse-conflict-json + - proc-log + - qrcode-terminal + - read + - semver + - spdx-expression-parse + - ssri + - supports-color + - tar + - text-table + - tiny-relative-date + - treeverse + - validate-npm-package-name + - which + - write-file-atomic + npmlog@5.0.1: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} deprecated: This package is no longer supported. - nwsapi@2.2.12: - resolution: {integrity: sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==} + nwsapi@2.2.16: + resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==} oauth4webapi@3.0.0: resolution: {integrity: sha512-Rw9SxQYuQX9J41VgM4rVNGtm1ng0Qcd8ndv7JmhmwqQ3hHBokX+WjV379IJhKk7bVPHefgvrDgHoO/rB2dY7YA==} @@ -6487,6 +7556,10 @@ packages: resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} engines: {node: '>= 0.4'} + object-inspect@1.13.3: + resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} + engines: {node: '>= 0.4'} + object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -6495,6 +7568,10 @@ packages: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + object.entries@1.1.8: resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} engines: {node: '>= 0.4'} @@ -6511,6 +7588,14 @@ packages: resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + octokit@4.1.0: + resolution: {integrity: sha512-/UrQAOSvkc+lUUWKNzy4ByAgYU9KpFzZQt8DnC962YmQuDiZb1SNJ90YukCCK5aMzKqqCA+z1kkAlmzYvdYKag==} + engines: {node: '>= 18'} + ofetch@1.4.1: resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} @@ -6527,6 +7612,10 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + openapi-path-templating@1.6.0: resolution: {integrity: sha512-1atBNwOUrZXthTvlvvX8k8ovFEF3iA8mDidYMkdOtvVdndBhTrspbwGXNOzEUaJhm9iUl4Tf5uQaeTLAJvwPig==} engines: {node: '>=12.20.0'} @@ -6535,8 +7624,8 @@ packages: resolution: {integrity: sha512-dtyTFKx2xVcO0W8JKaluXIHC9l/MLjHeflBaWjiWNMCHp/TBs9dEjQDbj/VFlHR4omFOKjjmqm1pW1aCAhmPBg==} engines: {node: '>=12.20.0'} - openapi3-ts@4.3.3: - resolution: {integrity: sha512-LKkzBGJcZ6wdvkKGMoSvpK+0cbN5Xc3XuYkJskO+vjEQWJgs1kgtyUk0pjf8KwPuysv323Er62F5P17XQl96Qg==} + openapi3-ts@4.4.0: + resolution: {integrity: sha512-9asTNB9IkKEzWMcHmVZE7Ts3kC9G7AFHfs8i7caD8HbI76gEjdkId4z/AkP83xdZsH7PLAnnbl47qZkXuxpArw==} optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} @@ -6557,10 +7646,30 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + p-each-series@3.0.0: + resolution: {integrity: sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==} + engines: {node: '>=12'} + + p-filter@4.1.0: + resolution: {integrity: sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==} + engines: {node: '>=18'} + + p-is-promise@3.0.0: + resolution: {integrity: sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==} + engines: {node: '>=8'} + + p-limit@1.3.0: + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@2.0.0: + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} + engines: {node: '>=4'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} @@ -6569,6 +7678,22 @@ packages: resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} engines: {node: '>=8'} + p-map@7.0.3: + resolution: {integrity: sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==} + engines: {node: '>=18'} + + p-reduce@2.1.0: + resolution: {integrity: sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==} + engines: {node: '>=8'} + + p-reduce@3.0.0: + resolution: {integrity: sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==} + engines: {node: '>=12'} + + p-try@1.0.0: + resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} + engines: {node: '>=4'} + pac-proxy-agent@7.0.2: resolution: {integrity: sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==} engines: {node: '>= 14'} @@ -6593,12 +7718,37 @@ packages: parse-entities@2.0.0: resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} + parse-json@4.0.0: + resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} + engines: {node: '>=4'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse-json@8.1.0: + resolution: {integrity: sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==} + engines: {node: '>=18'} + parse-ms@3.0.0: resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} engines: {node: '>=12'} - parse5@7.1.2: - resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + + parse5-htmlparser2-tree-adapter@6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + + parse5@5.1.1: + resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + + parse5@7.2.1: + resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} pascal-case@2.0.1: resolution: {integrity: sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==} @@ -6606,6 +7756,10 @@ packages: path-case@2.1.1: resolution: {integrity: sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==} + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -6618,6 +7772,10 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -6633,6 +7791,10 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + path-type@5.0.0: + resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} + engines: {node: '>=12'} + pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} @@ -6654,6 +7816,10 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} + pify@3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + piscina@4.6.1: resolution: {integrity: sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==} @@ -6661,16 +7827,30 @@ packages: resolution: {integrity: sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==} hasBin: true + pkg-conf@2.1.0: + resolution: {integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==} + engines: {node: '>=4'} + playwright-core@1.49.0: resolution: {integrity: sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==} engines: {node: '>=18'} hasBin: true + playwright-core@1.49.1: + resolution: {integrity: sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==} + engines: {node: '>=18'} + hasBin: true + playwright@1.49.0: resolution: {integrity: sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==} engines: {node: '>=18'} hasBin: true + playwright@1.49.1: + resolution: {integrity: sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==} + engines: {node: '>=18'} + hasBin: true + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -6741,8 +7921,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier-plugin-packagejson@2.5.6: - resolution: {integrity: sha512-TY7KiLtyt6Tlf53BEbXUWkN0+TRdHKgIMmtXtDCyHH6yWnZ50Lwq6Vb6lyjapZrhDTXooC4EtlY5iLe1sCgi5w==} + prettier-plugin-packagejson@2.5.8: + resolution: {integrity: sha512-BaGOF63I0IJZoudxpuQe17naV93BRtK8b3byWktkJReKEMX9CC4qdGUzThPDVO/AUhPzlqDiAXbp18U6X8wLKA==} peerDependencies: prettier: '>= 1.16.0' peerDependenciesMeta: @@ -6761,6 +7941,10 @@ packages: resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} engines: {node: '>=14.16'} + pretty-ms@9.2.0: + resolution: {integrity: sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==} + engines: {node: '>=18'} + pretty-print-error@1.1.2: resolution: {integrity: sha512-XkKN3W8aeRYApO17WpzuaJZmqH3WNSFeqR4Sxt7vu+C7pcWB+3+JDJ2dnnhzSCqvC1IaYR36CVh4VsFZyBicQA==} @@ -6853,6 +8037,9 @@ packages: proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + proxmox-api@1.1.1: + resolution: {integrity: sha512-2qH7pxKBBHa7WtEBmxPaBY2FZEH2R04hqr9zD9PmErLzJ7RGGcfNcXoS/v5G4vBM2Igmnx0EAYBstPwwfDwHnA==} + proxy-agent@6.4.0: resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} engines: {node: '>= 14'} @@ -6930,8 +8117,14 @@ packages: peerDependencies: react: ^19.0.0 - react-error-boundary@4.1.2: - resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} + react-dropzone-esm@15.2.0: + resolution: {integrity: sha512-pPwR8xWVL+tFLnbAb8KVH5f6Vtl397tck8dINkZ1cPMxHWH+l9dFmIgRWgbh7V7jbjIcuKXCsVrXbhQz68+dVA==} + engines: {node: '>= 10.13'} + peerDependencies: + react: '>= 16.8 || 18.0.0' + + react-error-boundary@5.0.0: + resolution: {integrity: sha512-tnjAxG+IkpLephNcePNA7v6F/QpWLH8He65+DmedchDwg162JZqx4NmbXj0mlAYVVEd81OW7aFhmbsScYfiAFQ==} peerDependencies: react: '>=16.13.1' @@ -6955,11 +8148,11 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-number-format@5.4.2: - resolution: {integrity: sha512-cg//jVdS49PYDgmcYoBnMMHl4XNTMuV723ZnHD2aXYtWWWqbVF3hjQ8iB+UZEuXapLbeA8P8H+1o6ZB1lcw3vg==} + react-number-format@5.4.3: + resolution: {integrity: sha512-VCY5hFg/soBighAoGcdE+GagkJq0230qN6jcS5sp8wQX1qy1fYN/RX7/BXkrs0oyzzwqR8/+eSUrqXbGeywdUQ==} peerDependencies: - react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-redux@9.1.2: resolution: {integrity: sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==} @@ -6977,22 +8170,22 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} - react-remove-scroll-bar@2.3.6: - resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true - react-remove-scroll@2.6.0: - resolution: {integrity: sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==} + react-remove-scroll@2.6.2: + resolution: {integrity: sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw==} engines: {node: '>=10'} peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -7007,12 +8200,12 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - react-style-singleton@2.2.1: - resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -7022,11 +8215,11 @@ packages: peerDependencies: react: '>= 0.14.0' - react-textarea-autosize@8.5.5: - resolution: {integrity: sha512-CVA94zmfp8m4bSHtWwmANaBR8EPsKy2aZ7KwqhoS4Ftib87F9Kvi7XQhOixypPLMc6kVYgOXvKFuuzZDpHGRPg==} + react-textarea-autosize@8.5.6: + resolution: {integrity: sha512-aT3ioKXMa8f6zHYGebhbdMD2L00tKeRX1zuVuDx9YQK/JLLRSaSxq3ugECEmUB9z2kvk6bFSIoRHLkkUv0RJiw==} engines: {node: '>=10'} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-transition-group@4.4.5: resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} @@ -7038,6 +8231,14 @@ packages: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} + read-package-up@11.0.0: + resolution: {integrity: sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==} + engines: {node: '>=18'} + + read-pkg@9.0.1: + resolution: {integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==} + engines: {node: '>=18'} + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -7076,8 +8277,8 @@ packages: redux@5.0.1: resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} - reflect.getprototypeof@1.0.6: - resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} + reflect.getprototypeof@1.0.9: + resolution: {integrity: sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q==} engines: {node: '>= 0.4'} refractor@3.6.0: @@ -7090,6 +8291,10 @@ packages: resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} engines: {node: '>= 0.4'} + regexp.prototype.flags@1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + engines: {node: '>= 0.4'} + registry-auth-token@3.3.2: resolution: {integrity: sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==} @@ -7131,6 +8336,10 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -7177,8 +8386,8 @@ packages: rrdom@0.1.7: resolution: {integrity: sha512-ZLd8f14z9pUy2Hk9y636cNv5Y2BMnNEY99wxzW9tD2BLDfe1xFxtLjB4q/xCBYo6HRe0wofzKzjm4JojmpBfFw==} - rrweb-cssom@0.7.1: - resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + rrweb-cssom@0.8.0: + resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} rrweb-player@1.0.0-alpha.4: resolution: {integrity: sha512-Wlmn9GZ5Fdqa37vd3TzsYdLl/JWEvXNUrLCrYpnOwEgmY409HwVIvvA5aIo7k582LoKgdRCsB87N+f0oWAR0Kg==} @@ -7210,6 +8419,10 @@ packages: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -7220,6 +8433,10 @@ packages: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + safe-stable-stringify@2.5.0: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} engines: {node: '>=10'} @@ -7227,8 +8444,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass@1.83.0: - resolution: {integrity: sha512-qsSxlayzoOjdvXMVLkzF84DJFc2HZEL/rFyGIKbbilYtAvlCxyuzUeff9LawTn4btVnLKg75Z8MMr1lxU1lfGw==} + sass@1.83.4: + resolution: {integrity: sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA==} engines: {node: '>=14.0.0'} hasBin: true @@ -7246,10 +8463,26 @@ packages: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} + semantic-release@24.2.1: + resolution: {integrity: sha512-z0/3cutKNkLQ4Oy0HTi3lubnjTsdjjgOqmxdPjeYWe6lhFqUPfwslZxRHv3HDZlN4MhnZitb9SLihDkZNxOXfQ==} + engines: {node: '>=20.8.1'} + hasBin: true + semver-diff@3.1.1: resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==} engines: {node: '>=8'} + semver-diff@4.0.0: + resolution: {integrity: sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==} + engines: {node: '>=12'} + + semver-parser@4.1.7: + resolution: {integrity: sha512-RNNvmr1JKZ4Eia7Cyfxtr6aR7eiQs1bPGBv4EC3OJ5pTKEoHjLsT+dY1SSny2tq/uqx9bzNR4lL8tzaB70TN9A==} + + semver-regex@4.0.5: + resolution: {integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==} + engines: {node: '>=12'} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -7295,6 +8528,10 @@ packages: resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} hasBin: true + sharp@0.33.5: + resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -7310,8 +8547,20 @@ packages: resolution: {integrity: sha512-cMGfwNyfDZ/nzJ2k2M+ClthBIh//GlZl1JEf47Uoa9XR11bz8Pa2T2wQO4bVrRdH48LrIDWJahQziKo3MjhsWg==} hasBin: true - side-channel@1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} siginfo@2.0.0: @@ -7324,6 +8573,10 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + signale@1.4.0: + resolution: {integrity: sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==} + engines: {node: '>=6'} + simple-concat@1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} @@ -7340,10 +8593,18 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + skin-tone@2.0.0: + resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} + engines: {node: '>=8'} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -7377,8 +8638,8 @@ packages: sort-object-keys@1.1.3: resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==} - sort-package-json@2.12.0: - resolution: {integrity: sha512-/HrPQAeeLaa+vbAH/znjuhwUluuiM/zL5XX9kop8UpDgjtyWKt43hGDk2vd/TBdDpzIyzIHVUgmYofzYrAQjew==} + sort-package-json@2.14.0: + resolution: {integrity: sha512-xBRdmMjFB/KW3l51mP31dhlaiFmqkHLfWTfZAno8prb/wbDxwBPWFpxB16GZbiPbYr3wL41H8Kx22QIDWRe8WQ==} hasBin: true source-map-js@1.2.1: @@ -7395,9 +8656,27 @@ packages: space-separated-tokens@1.1.5: resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==} + spawn-error-forwarder@1.0.0: + resolution: {integrity: sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.20: + resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} + split-ca@1.0.1: resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} + split2@1.0.0: + resolution: {integrity: sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -7431,6 +8710,9 @@ packages: std-env@3.8.0: resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + stream-combiner2@1.1.1: + resolution: {integrity: sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==} + streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -7453,13 +8735,17 @@ packages: resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} engines: {node: '>= 0.4'} - string.prototype.matchall@4.0.11: - resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} string.prototype.repeat@1.0.0: resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + string.prototype.trim@1.2.9: resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} @@ -7467,6 +8753,10 @@ packages: string.prototype.trimend@1.0.8: resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + string.prototype.trimstart@1.0.8: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} @@ -7493,6 +8783,14 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} @@ -7504,13 +8802,13 @@ packages: strnum@1.0.5: resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} - styled-jsx@5.1.1: - resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} engines: {node: '>= 12.0.0'} peerDependencies: '@babel/core': '*' babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' peerDependenciesMeta: '@babel/core': optional: true @@ -7526,6 +8824,10 @@ packages: peerDependencies: postcss: ^8.3.3 + super-regex@1.0.0: + resolution: {integrity: sha512-CY8u7DtbvucKuquCmOFEKhr9Besln7n9uN8eFbwcoGYWXOMW07u2o8njWaiXt11ylS3qoGF55pILjRmPlbodyg==} + engines: {node: '>=18'} + superjson@2.2.2: resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} engines: {node: '>=16'} @@ -7542,6 +8844,10 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + supports-hyperlinks@3.1.0: + resolution: {integrity: sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==} + engines: {node: '>=14.18'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -7592,6 +8898,14 @@ packages: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + + tempy@3.1.0: + resolution: {integrity: sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==} + engines: {node: '>=14.16'} + terser-webpack-plugin@5.3.10: resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} engines: {node: '>= 10.13.0'} @@ -7626,9 +8940,23 @@ packages: text-hex@1.0.0: resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + through2@2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + time-span@5.1.0: + resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==} + engines: {node: '>=12'} + tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -7666,11 +8994,11 @@ packages: title-case@2.1.1: resolution: {integrity: sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==} - tldts-core@6.1.67: - resolution: {integrity: sha512-12K5O4m3uUW6YM5v45Z7wc6NTSmAYj4Tq3de7eXghZkp879IlfPJrUWeWFwu1FS94U5t2vwETgJ1asu8UGNKVQ==} + tldts-core@6.1.69: + resolution: {integrity: sha512-nygxy9n2PBUFQUtAXAc122gGo+04/j5qr5TGQFZTHafTKYvmARVXt2cA5rgero2/dnXUfkdPtiJoKmrd3T+wdA==} - tldts@6.1.67: - resolution: {integrity: sha512-714VbegxoZ9WF5/IsVCy9rWXKUpPkJq87ebWLXQzNawce96l5oRrRf2eHzB4pT2g/4HQU1dYbu+sdXClYxlDKQ==} + tldts@6.1.69: + resolution: {integrity: sha512-Oh/CqRQ1NXNY7cy9NkTPUauOWiTro0jEYZTioGbOmcQh6EC45oribyIMJp0OJO3677r13tO6SKdWoGZUx2BDFw==} hasBin: true tmp@0.0.33: @@ -7685,6 +9013,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toad-cache@3.7.0: + resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} + engines: {node: '>=12'} + toggle-selection@1.0.6: resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} @@ -7707,6 +9039,10 @@ packages: resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} engines: {node: '>=18'} + traverse@0.6.8: + resolution: {integrity: sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==} + engines: {node: '>= 0.4'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -7724,18 +9060,18 @@ packages: resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} engines: {node: '>= 14.0.0'} - trpc-to-openapi@2.1.0: - resolution: {integrity: sha512-LODbI2a9LQamLpEz9hsqeMJBxpNT8KqfyICJhTVe8JBPZM8DvUkoICPlsdHf1KJVteoem/LlbwkD7loKYPWP1Q==} + trpc-to-openapi@2.1.2: + resolution: {integrity: sha512-v6GmrXchDdHUGtPz0foviSYZBkNQePmZF4fvnw8TPhdyDFdiMpVHbkz8QNIWVeqPOG6qKAyCVAvXTO+14/dHWw==} peerDependencies: '@trpc/server': ^11.0.0-rc.648 zod: ^3.23.8 zod-openapi: ^4.1.0 - ts-api-utils@1.3.0: - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} + ts-api-utils@2.0.0: + resolution: {integrity: sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==} + engines: {node: '>=18.12'} peerDependencies: - typescript: '>=4.2.0' + typescript: '>=4.8.4' ts-mixer@6.0.4: resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} @@ -7776,6 +9112,9 @@ packages: tslib@2.7.0: resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsscmp@1.0.6: resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} engines: {node: '>=0.6.x'} @@ -7837,8 +9176,16 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - type-fest@4.28.0: - resolution: {integrity: sha512-jXMwges/FVbFRe5lTMJZVEZCrO9kI9c8k0PA/z7nF3bo0JSCCLysvokFjNPIUK/itEMas10MQM+AiHoHt/T/XA==} + type-fest@1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + + type-fest@4.30.2: + resolution: {integrity: sha512-UJShLPYi1aWqCdq9HycOL/gwsuqda1OISdBO3t8RlXQC4QvtuIz4b5FCfe2dQIWEpmlRExKmcTBfP1r9bhY7ig==} engines: {node: '>=16'} type-is@1.6.18: @@ -7849,33 +9196,49 @@ packages: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.1: resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + typed-array-byte-offset@1.0.2: resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} engines: {node: '>= 0.4'} + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + typed-array-length@1.0.6: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} types-ramda@0.30.1: resolution: {integrity: sha512-1HTsf5/QVRmLzcGfldPFvkVsAdi1db1BBKzi7iW3KBUlOICg/nKnFS+jGqDJS3YD8VsWbAh7JiHeBvbsw8RPxA==} - typescript-eslint@8.18.0: - resolution: {integrity: sha512-Xq2rRjn6tzVpAyHr3+nmSg1/9k9aIHnJ2iZeOH7cfGOWqTkXTm3kwpQglEuLGdNrYvPF+2gtAs+/KF5rjVo+WQ==} + typescript-eslint@8.20.0: + resolution: {integrity: sha512-Kxz2QRFsgbWj6Xcftlw3Dd154b3cEPFqQC+qMZrMypSijPd4UanKKvoKDrJ4o8AIfZFKAF+7sMaEIR8mTElozA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - typescript@5.7.2: - resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} engines: {node: '>=14.17'} hasBin: true @@ -7897,6 +9260,10 @@ packages: unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} @@ -7910,17 +9277,39 @@ packages: resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} engines: {node: '>=14.0'} - undici@7.1.0: - resolution: {integrity: sha512-3+mdX2R31khuLCm2mKExSlMdJsfol7bJkIMH80tdXA74W34rT1jKemUTlYR7WY3TqsV4wfOgpatWmmB2Jl1+5g==} + undici@7.2.3: + resolution: {integrity: sha512-2oSLHaDalSt2/O/wHA9M+/ZPAOcU2yrSP/cdBYJ+YxZskiPYDSqHbysLSlD7gq3JMqOoJI5O31RVU3BxX/MnAA==} engines: {node: '>=20.18.1'} unenv@1.10.0: resolution: {integrity: sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ==} + unicode-emoji-modifier-base@1.0.0: + resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} + engines: {node: '>=4'} + + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + unique-string@2.0.0: resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} engines: {node: '>=8'} + unique-string@3.0.0: + resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} + engines: {node: '>=12'} + + universal-github-app-jwt@2.2.0: + resolution: {integrity: sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ==} + + universal-user-agent@7.0.2: + resolution: {integrity: sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -7963,18 +9352,22 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-join@5.0.0: + resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} url-toolkit@2.2.5: resolution: {integrity: sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg==} - use-callback-ref@1.3.2: - resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -7990,8 +9383,8 @@ packages: peerDependencies: react: '>=16.13' - use-intl@3.26.1: - resolution: {integrity: sha512-MZhtSBcMrDna3xs1T6O7CAXx4wRfm1eGyUYrDCCnW9qTOGZurCH5k/X6ChDl6EI4f+qYEtXQCRMkQUVOIhJWTQ==} + use-intl@3.26.3: + resolution: {integrity: sha512-yY0a2YseO17cKwHA9M6fcpiEJ2Uo81DEU0NOUxNTp6lJVNOuI6nULANPVVht6IFdrYFtlsMmMoc97+Eq9/Tnng==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0 @@ -8031,8 +9424,8 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - uuid@11.0.3: - resolution: {integrity: sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==} + uuid@11.0.4: + resolution: {integrity: sha512-IzL6VtTTYcAhA/oghbFJ1Dkmqev+FpQWnCBaKq/gUluLxliWvO8DPFWfIviRmYbtaavtSQe4WBL++rFjdcGWEg==} hasBin: true uuid@8.3.2: @@ -8042,6 +9435,9 @@ packages: v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + validate-npm-package-name@5.0.1: resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -8190,8 +9586,8 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - whatwg-url@14.0.0: - resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==} + whatwg-url@14.1.0: + resolution: {integrity: sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==} engines: {node: '>=18'} whatwg-url@5.0.0: @@ -8200,8 +9596,12 @@ packages: which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - which-builtin-type@1.1.4: - resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==} + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} engines: {node: '>= 0.4'} which-collection@1.0.2: @@ -8212,6 +9612,10 @@ packages: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} + which-typed-array@1.1.18: + resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} + engines: {node: '>= 0.4'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -8337,10 +9741,18 @@ packages: engines: {node: '>= 14'} hasBin: true + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -8353,6 +9765,10 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yoctocolors@2.1.1: + resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} + engines: {node: '>=18'} + zenscroll@4.0.2: resolution: {integrity: sha512-jEA1znR7b4C/NnaycInCU6h/d15ZzCd1jmsruqOKnZP6WXQSMH3W2GL+OXbkruslU4h+Tzuos0HdswzRUk/Vgg==} @@ -8360,8 +9776,8 @@ packages: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} - zod-form-data@2.0.2: - resolution: {integrity: sha512-sKTi+k0fvkxdakD0V5rq+9WVJA3cuTQUfEmNqvHrTzPLvjfLmkkBLfR0ed3qOi9MScJXTHIDH/jUNnEJ3CBX4g==} + zod-form-data@2.0.5: + resolution: {integrity: sha512-T7dV6lTBCwkd8PyvJVCnjXKpgXomU8gEm/TcvEZY7qNdRhIo9T17HrdlHIK68PzTAYaV2HxR9rgwpTSWv0L+QQ==} peerDependencies: zod: '>= 3.11.0' @@ -8383,6 +9799,14 @@ snapshots: '@antfu/ni@0.21.12': {} + '@asamuzakjp/css-color@2.8.2': + dependencies: + '@csstools/css-calc': 2.1.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) + '@csstools/css-color-parser': 3.0.7(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 + lru-cache: 11.0.2 + '@auth/core@0.37.2': dependencies: '@panva/hkdf': 1.2.1 @@ -8435,7 +9859,7 @@ snapshots: '@babel/traverse': 7.25.9 '@babel/types': 7.26.0 convert-source-map: 2.0.0 - debug: 4.3.7 + debug: 4.4.0 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -8523,7 +9947,7 @@ snapshots: '@babel/parser': 7.26.2 '@babel/template': 7.25.9 '@babel/types': 7.26.0 - debug: 4.3.7 + debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -8556,19 +9980,43 @@ snapshots: picocolors: 1.1.0 sisteransi: 1.0.5 + '@colors/colors@1.5.0': + optional: true + '@colors/colors@1.6.0': {} '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@ctrl/deluge@7.0.0': + '@csstools/color-helpers@5.0.1': {} + + '@csstools/css-calc@2.1.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 + + '@csstools/css-color-parser@3.0.7(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)': + dependencies: + '@csstools/color-helpers': 5.0.1 + '@csstools/css-calc': 2.1.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) + '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3) + '@csstools/css-tokenizer': 3.0.3 + + '@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3)': + dependencies: + '@csstools/css-tokenizer': 3.0.3 + + '@csstools/css-tokenizer@3.0.3': {} + + '@ctrl/deluge@7.1.0': dependencies: '@ctrl/magnet-link': 4.0.2 - '@ctrl/shared-torrent': 6.1.0 + '@ctrl/shared-torrent': 6.2.1 node-fetch-native: 1.6.4 ofetch: 1.4.1 tough-cookie: 5.0.0 + type-fest: 4.30.2 ufo: 1.5.4 uint8array-extras: 1.4.0 @@ -8577,28 +10025,30 @@ snapshots: rfc4648: 1.5.3 uint8array-extras: 1.4.0 - '@ctrl/qbittorrent@9.1.0': + '@ctrl/qbittorrent@9.2.0': dependencies: '@ctrl/magnet-link': 4.0.2 - '@ctrl/shared-torrent': 6.1.0 + '@ctrl/shared-torrent': 6.2.1 '@ctrl/torrent-file': 4.1.0 - cookie: 1.0.1 + cookie: 1.0.2 node-fetch-native: 1.6.4 ofetch: 1.4.1 + type-fest: 4.30.2 ufo: 1.5.4 uint8array-extras: 1.4.0 - '@ctrl/shared-torrent@6.1.0': {} + '@ctrl/shared-torrent@6.2.1': {} '@ctrl/torrent-file@4.1.0': dependencies: uint8array-extras: 1.4.0 - '@ctrl/transmission@7.1.0': + '@ctrl/transmission@7.2.0': dependencies: '@ctrl/magnet-link': 4.0.2 - '@ctrl/shared-torrent': 6.1.0 + '@ctrl/shared-torrent': 6.2.1 ofetch: 1.4.1 + type-fest: 4.30.2 ufo: 1.5.4 uint8array-extras: 1.4.0 @@ -8637,6 +10087,11 @@ snapshots: '@drizzle-team/brocli@0.11.0': {} + '@emnapi/runtime@1.3.1': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild-kit/core-utils@3.3.2': dependencies: esbuild: 0.18.20 @@ -8992,9 +10447,9 @@ snapshots: '@esbuild/win32-x64@0.23.1': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@9.16.0)': + '@eslint-community/eslint-utils@4.4.0(eslint@9.18.0)': dependencies: - eslint: 9.16.0 + eslint: 9.18.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -9002,17 +10457,19 @@ snapshots: '@eslint/config-array@0.19.0': dependencies: '@eslint/object-schema': 2.1.4 - debug: 4.3.7 + debug: 4.4.0 minimatch: 3.1.2 transitivePeerDependencies: - supports-color - '@eslint/core@0.9.0': {} + '@eslint/core@0.10.0': + dependencies: + '@types/json-schema': 7.0.15 '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 - debug: 4.3.7 + debug: 4.4.0 espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -9023,12 +10480,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.16.0': {} + '@eslint/js@9.18.0': {} '@eslint/object-schema@2.1.4': {} - '@eslint/plugin-kit@0.2.3': + '@eslint/plugin-kit@0.2.5': dependencies: + '@eslint/core': 0.10.0 levn: 0.4.1 '@extractus/feed-extractor@7.1.3': @@ -9071,22 +10529,22 @@ snapshots: dependencies: '@formatjs/fast-memoize': 2.2.1 '@formatjs/intl-localematcher': 0.5.5 - tslib: 2.7.0 + tslib: 2.8.1 '@formatjs/fast-memoize@2.2.1': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 '@formatjs/icu-messageformat-parser@2.8.0': dependencies: '@formatjs/ecma402-abstract': 2.2.0 '@formatjs/icu-skeleton-parser': 1.8.4 - tslib: 2.7.0 + tslib: 2.8.1 '@formatjs/icu-skeleton-parser@1.8.4': dependencies: '@formatjs/ecma402-abstract': 2.2.0 - tslib: 2.7.0 + tslib: 2.8.1 '@formatjs/intl-localematcher@0.5.5': dependencies: @@ -9094,7 +10552,7 @@ snapshots: '@hapi/bourne@3.0.0': {} - '@homarr/gridstack@1.11.2': {} + '@homarr/gridstack@1.11.3': {} '@hono/node-server@1.13.0(hono@4.6.1)': dependencies: @@ -9113,7 +10571,7 @@ snapshots: '@humanwhocodes/retry@0.4.1': {} - '@ianvs/prettier-plugin-sort-imports@4.4.0(prettier@3.4.2)': + '@ianvs/prettier-plugin-sort-imports@4.4.1(prettier@3.4.2)': dependencies: '@babel/generator': 7.26.2 '@babel/parser': 7.26.2 @@ -9124,6 +10582,81 @@ snapshots: transitivePeerDependencies: - supports-color + '@img/sharp-darwin-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.0.4 + optional: true + + '@img/sharp-darwin-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.0.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.0.5': + optional: true + + '@img/sharp-libvips-linux-s390x@1.0.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + optional: true + + '@img/sharp-linux-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.0.4 + optional: true + + '@img/sharp-linux-arm@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.0.5 + optional: true + + '@img/sharp-linux-s390x@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.0.4 + optional: true + + '@img/sharp-linux-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + optional: true + + '@img/sharp-wasm32@0.33.5': + dependencies: + '@emnapi/runtime': 1.3.1 + optional: true + + '@img/sharp-win32-ia32@0.33.5': + optional: true + + '@img/sharp-win32-x64@0.33.5': + optional: true + '@ioredis/commands@1.2.0': {} '@isaacs/cliui@8.0.2': @@ -9179,100 +10712,85 @@ snapshots: js-base64: 3.7.7 optional: true - '@mantine/colors-generator@7.15.1(chroma-js@3.1.2)': + '@mantine/colors-generator@7.16.0(chroma-js@3.1.2)': dependencies: chroma-js: 3.1.2 - '@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@floating-ui/react': 0.26.28(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/hooks': 7.15.1(react@19.0.0) + '@mantine/hooks': 7.16.0(react@19.0.0) clsx: 2.1.1 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - react-number-format: 5.4.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-remove-scroll: 2.6.0(@types/react@18.3.13)(react@19.0.0) - react-textarea-autosize: 8.5.5(@types/react@18.3.13)(react@19.0.0) - type-fest: 4.28.0 + react-number-format: 5.4.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-remove-scroll: 2.6.2(@types/react@19.0.7)(react@19.0.0) + react-textarea-autosize: 8.5.6(@types/react@19.0.7)(react@19.0.0) + type-fest: 4.30.2 transitivePeerDependencies: - '@types/react' - '@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@mantine/dates@7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@floating-ui/react': 0.26.28(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/hooks': 7.15.1(react@19.0.0) - clsx: 2.1.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-number-format: 5.4.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-remove-scroll: 2.6.0(@types/react@19.0.1)(react@19.0.0) - react-textarea-autosize: 8.5.5(@types/react@19.0.1)(react@19.0.0) - type-fest: 4.28.0 - transitivePeerDependencies: - - '@types/react' - - '@mantine/dates@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@mantine/core': 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/hooks': 7.15.1(react@19.0.0) + '@mantine/core': 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/hooks': 7.16.0(react@19.0.0) clsx: 2.1.1 dayjs: 1.11.13 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - '@mantine/dates@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@mantine/dropzone@7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@mantine/core': 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/hooks': 7.15.1(react@19.0.0) - clsx: 2.1.1 - dayjs: 1.11.13 + '@mantine/core': 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/hooks': 7.16.0(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) + react-dropzone-esm: 15.2.0(react@19.0.0) - '@mantine/form@7.15.1(react@19.0.0)': + '@mantine/form@7.16.0(react@19.0.0)': dependencies: fast-deep-equal: 3.1.3 klona: 2.0.6 react: 19.0.0 - '@mantine/hooks@7.15.1(react@19.0.0)': + '@mantine/hooks@7.16.0(react@19.0.0)': dependencies: react: 19.0.0 - '@mantine/modals@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@mantine/modals@7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@mantine/core': 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/hooks': 7.15.1(react@19.0.0) + '@mantine/core': 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/hooks': 7.16.0(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - '@mantine/notifications@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@mantine/notifications@7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@mantine/core': 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/hooks': 7.15.1(react@19.0.0) - '@mantine/store': 7.15.1(react@19.0.0) + '@mantine/core': 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/hooks': 7.16.0(react@19.0.0) + '@mantine/store': 7.16.0(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/spotlight@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@mantine/spotlight@7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@mantine/core': 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/hooks': 7.15.1(react@19.0.0) - '@mantine/store': 7.15.1(react@19.0.0) + '@mantine/core': 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/hooks': 7.16.0(react@19.0.0) + '@mantine/store': 7.16.0(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - '@mantine/store@7.15.1(react@19.0.0)': + '@mantine/store@7.16.0(react@19.0.0)': dependencies: react: 19.0.0 - '@mantine/tiptap@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(@tiptap/extension-link@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3))(@tiptap/react@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@mantine/tiptap@7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(@tiptap/extension-link@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2))(@tiptap/react@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@mantine/core': 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/hooks': 7.15.1(react@19.0.0) - '@tiptap/extension-link': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/react': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/core': 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/hooks': 7.16.0(react@19.0.0) + '@tiptap/extension-link': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/react': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) @@ -9344,37 +10862,34 @@ snapshots: - utf-8-validate - webpack-sources - '@next/env@14.2.20': {} + '@next/env@15.1.4': {} - '@next/eslint-plugin-next@14.2.20': + '@next/eslint-plugin-next@15.1.4': dependencies: - glob: 10.3.10 + fast-glob: 3.3.1 - '@next/swc-darwin-arm64@14.2.20': + '@next/swc-darwin-arm64@15.1.4': optional: true - '@next/swc-darwin-x64@14.2.20': + '@next/swc-darwin-x64@15.1.4': optional: true - '@next/swc-linux-arm64-gnu@14.2.20': + '@next/swc-linux-arm64-gnu@15.1.4': optional: true - '@next/swc-linux-arm64-musl@14.2.20': + '@next/swc-linux-arm64-musl@15.1.4': optional: true - '@next/swc-linux-x64-gnu@14.2.20': + '@next/swc-linux-x64-gnu@15.1.4': optional: true - '@next/swc-linux-x64-musl@14.2.20': + '@next/swc-linux-x64-musl@15.1.4': optional: true - '@next/swc-win32-arm64-msvc@14.2.20': + '@next/swc-win32-arm64-msvc@15.1.4': optional: true - '@next/swc-win32-ia32-msvc@14.2.20': - optional: true - - '@next/swc-win32-x64-msvc@14.2.20': + '@next/swc-win32-x64-msvc@15.1.4': optional: true '@noble/hashes@1.5.0': {} @@ -9391,6 +10906,204 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + '@octokit/app@15.1.2': + dependencies: + '@octokit/auth-app': 7.1.4 + '@octokit/auth-unauthenticated': 6.1.1 + '@octokit/core': 6.1.3 + '@octokit/oauth-app': 7.1.5 + '@octokit/plugin-paginate-rest': 11.4.0(@octokit/core@6.1.3) + '@octokit/types': 13.7.0 + '@octokit/webhooks': 13.4.2 + + '@octokit/auth-app@7.1.4': + dependencies: + '@octokit/auth-oauth-app': 8.1.2 + '@octokit/auth-oauth-user': 5.1.2 + '@octokit/request': 9.1.4 + '@octokit/request-error': 6.1.6 + '@octokit/types': 13.7.0 + toad-cache: 3.7.0 + universal-github-app-jwt: 2.2.0 + universal-user-agent: 7.0.2 + + '@octokit/auth-oauth-app@8.1.2': + dependencies: + '@octokit/auth-oauth-device': 7.1.2 + '@octokit/auth-oauth-user': 5.1.2 + '@octokit/request': 9.1.4 + '@octokit/types': 13.7.0 + universal-user-agent: 7.0.2 + + '@octokit/auth-oauth-device@7.1.2': + dependencies: + '@octokit/oauth-methods': 5.1.3 + '@octokit/request': 9.1.4 + '@octokit/types': 13.7.0 + universal-user-agent: 7.0.2 + + '@octokit/auth-oauth-user@5.1.2': + dependencies: + '@octokit/auth-oauth-device': 7.1.2 + '@octokit/oauth-methods': 5.1.3 + '@octokit/request': 9.1.4 + '@octokit/types': 13.7.0 + universal-user-agent: 7.0.2 + + '@octokit/auth-token@5.1.1': {} + + '@octokit/auth-unauthenticated@6.1.1': + dependencies: + '@octokit/request-error': 6.1.6 + '@octokit/types': 13.7.0 + + '@octokit/core@6.1.2': + dependencies: + '@octokit/auth-token': 5.1.1 + '@octokit/graphql': 8.1.1 + '@octokit/request': 9.1.3 + '@octokit/request-error': 6.1.5 + '@octokit/types': 13.6.2 + before-after-hook: 3.0.2 + universal-user-agent: 7.0.2 + + '@octokit/core@6.1.3': + dependencies: + '@octokit/auth-token': 5.1.1 + '@octokit/graphql': 8.1.2 + '@octokit/request': 9.1.4 + '@octokit/request-error': 6.1.6 + '@octokit/types': 13.7.0 + before-after-hook: 3.0.2 + universal-user-agent: 7.0.2 + + '@octokit/endpoint@10.1.1': + dependencies: + '@octokit/types': 13.6.2 + universal-user-agent: 7.0.2 + + '@octokit/graphql@8.1.1': + dependencies: + '@octokit/request': 9.1.3 + '@octokit/types': 13.6.2 + universal-user-agent: 7.0.2 + + '@octokit/graphql@8.1.2': + dependencies: + '@octokit/request': 9.1.4 + '@octokit/types': 13.7.0 + universal-user-agent: 7.0.2 + + '@octokit/oauth-app@7.1.5': + dependencies: + '@octokit/auth-oauth-app': 8.1.2 + '@octokit/auth-oauth-user': 5.1.2 + '@octokit/auth-unauthenticated': 6.1.1 + '@octokit/core': 6.1.3 + '@octokit/oauth-authorization-url': 7.1.1 + '@octokit/oauth-methods': 5.1.3 + '@types/aws-lambda': 8.10.146 + universal-user-agent: 7.0.2 + + '@octokit/oauth-authorization-url@7.1.1': {} + + '@octokit/oauth-methods@5.1.3': + dependencies: + '@octokit/oauth-authorization-url': 7.1.1 + '@octokit/request': 9.1.4 + '@octokit/request-error': 6.1.6 + '@octokit/types': 13.7.0 + + '@octokit/openapi-types@22.2.0': {} + + '@octokit/openapi-types@23.0.1': {} + + '@octokit/openapi-webhooks-types@8.5.1': {} + + '@octokit/plugin-paginate-graphql@5.2.4(@octokit/core@6.1.3)': + dependencies: + '@octokit/core': 6.1.3 + + '@octokit/plugin-paginate-rest@11.3.6(@octokit/core@6.1.2)': + dependencies: + '@octokit/core': 6.1.2 + '@octokit/types': 13.6.2 + + '@octokit/plugin-paginate-rest@11.4.0(@octokit/core@6.1.3)': + dependencies: + '@octokit/core': 6.1.3 + '@octokit/types': 13.7.0 + + '@octokit/plugin-rest-endpoint-methods@13.3.0(@octokit/core@6.1.3)': + dependencies: + '@octokit/core': 6.1.3 + '@octokit/types': 13.7.0 + + '@octokit/plugin-retry@7.1.2(@octokit/core@6.1.2)': + dependencies: + '@octokit/core': 6.1.2 + '@octokit/request-error': 6.1.5 + '@octokit/types': 13.6.2 + bottleneck: 2.19.5 + + '@octokit/plugin-retry@7.1.3(@octokit/core@6.1.3)': + dependencies: + '@octokit/core': 6.1.3 + '@octokit/request-error': 6.1.6 + '@octokit/types': 13.7.0 + bottleneck: 2.19.5 + + '@octokit/plugin-throttling@9.3.2(@octokit/core@6.1.2)': + dependencies: + '@octokit/core': 6.1.2 + '@octokit/types': 13.6.2 + bottleneck: 2.19.5 + + '@octokit/plugin-throttling@9.4.0(@octokit/core@6.1.3)': + dependencies: + '@octokit/core': 6.1.3 + '@octokit/types': 13.7.0 + bottleneck: 2.19.5 + + '@octokit/request-error@6.1.5': + dependencies: + '@octokit/types': 13.6.2 + + '@octokit/request-error@6.1.6': + dependencies: + '@octokit/types': 13.7.0 + + '@octokit/request@9.1.3': + dependencies: + '@octokit/endpoint': 10.1.1 + '@octokit/request-error': 6.1.5 + '@octokit/types': 13.6.2 + universal-user-agent: 7.0.2 + + '@octokit/request@9.1.4': + dependencies: + '@octokit/endpoint': 10.1.1 + '@octokit/request-error': 6.1.6 + '@octokit/types': 13.7.0 + fast-content-type-parse: 2.0.1 + universal-user-agent: 7.0.2 + + '@octokit/types@13.6.2': + dependencies: + '@octokit/openapi-types': 22.2.0 + + '@octokit/types@13.7.0': + dependencies: + '@octokit/openapi-types': 23.0.1 + + '@octokit/webhooks-methods@5.1.0': {} + + '@octokit/webhooks@13.4.2': + dependencies: + '@octokit/openapi-webhooks-types': 8.5.1 + '@octokit/request-error': 6.1.6 + '@octokit/webhooks-methods': 5.1.0 + '@panva/hkdf@1.2.1': {} '@paralleldrive/cuid2@2.2.2': @@ -9459,6 +11172,11 @@ snapshots: '@pkgr/core@0.1.1': {} + '@playwright/test@1.49.1': + dependencies: + playwright: 1.49.1 + optional: true + '@pnpm/config.env-replace@1.1.0': {} '@pnpm/network.ca-file@1.0.2': @@ -9544,6 +11262,109 @@ snapshots: '@scarf/scarf@1.4.0': {} + '@sec-ant/readable-stream@0.4.1': {} + + '@semantic-release/changelog@6.0.3(semantic-release@24.2.1(typescript@5.7.3))': + dependencies: + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + fs-extra: 11.2.0 + lodash: 4.17.21 + semantic-release: 24.2.1(typescript@5.7.3) + + '@semantic-release/commit-analyzer@13.0.1(semantic-release@24.2.1(typescript@5.7.3))': + dependencies: + conventional-changelog-angular: 8.0.0 + conventional-changelog-writer: 8.0.0 + conventional-commits-filter: 5.0.0 + conventional-commits-parser: 6.0.0 + debug: 4.4.0 + import-from-esm: 2.0.0 + lodash-es: 4.17.21 + micromatch: 4.0.8 + semantic-release: 24.2.1(typescript@5.7.3) + transitivePeerDependencies: + - supports-color + + '@semantic-release/error@3.0.0': {} + + '@semantic-release/error@4.0.0': {} + + '@semantic-release/git@10.0.1(semantic-release@24.2.1(typescript@5.7.3))': + dependencies: + '@semantic-release/error': 3.0.0 + aggregate-error: 3.1.0 + debug: 4.3.7 + dir-glob: 3.0.1 + execa: 5.1.1 + lodash: 4.17.21 + micromatch: 4.0.8 + p-reduce: 2.1.0 + semantic-release: 24.2.1(typescript@5.7.3) + transitivePeerDependencies: + - supports-color + + '@semantic-release/github@11.0.1(semantic-release@24.2.1(typescript@5.7.3))': + dependencies: + '@octokit/core': 6.1.2 + '@octokit/plugin-paginate-rest': 11.3.6(@octokit/core@6.1.2) + '@octokit/plugin-retry': 7.1.2(@octokit/core@6.1.2) + '@octokit/plugin-throttling': 9.3.2(@octokit/core@6.1.2) + '@semantic-release/error': 4.0.0 + aggregate-error: 5.0.0 + debug: 4.3.7 + dir-glob: 3.0.1 + globby: 14.0.2 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + issue-parser: 7.0.1 + lodash-es: 4.17.21 + mime: 4.0.4 + p-filter: 4.1.0 + semantic-release: 24.2.1(typescript@5.7.3) + url-join: 5.0.0 + transitivePeerDependencies: + - supports-color + + '@semantic-release/npm@12.0.1(semantic-release@24.2.1(typescript@5.7.3))': + dependencies: + '@semantic-release/error': 4.0.0 + aggregate-error: 5.0.0 + execa: 9.5.2 + fs-extra: 11.2.0 + lodash-es: 4.17.21 + nerf-dart: 1.0.0 + normalize-url: 8.0.1 + npm: 10.9.2 + rc: 1.2.8 + read-pkg: 9.0.1 + registry-auth-token: 5.0.2 + semantic-release: 24.2.1(typescript@5.7.3) + semver: 7.6.3 + tempy: 3.1.0 + + '@semantic-release/release-notes-generator@14.0.3(semantic-release@24.2.1(typescript@5.7.3))': + dependencies: + conventional-changelog-angular: 8.0.0 + conventional-changelog-writer: 8.0.0 + conventional-commits-filter: 5.0.0 + conventional-commits-parser: 6.0.0 + debug: 4.4.0 + get-stream: 7.0.1 + import-from-esm: 2.0.0 + into-stream: 7.0.0 + lodash-es: 4.17.21 + read-package-up: 11.0.0 + semantic-release: 24.2.1(typescript@5.7.3) + transitivePeerDependencies: + - supports-color + + '@sindresorhus/is@4.6.0': {} + + '@sindresorhus/merge-streams@2.3.0': {} + + '@sindresorhus/merge-streams@4.0.0': {} + '@socket.io/component-emitter@3.1.2': {} '@swagger-api/apidom-ast@1.0.0-alpha.9': @@ -9880,54 +11701,53 @@ snapshots: '@swc/counter@0.1.3': {} - '@swc/helpers@0.5.5': + '@swc/helpers@0.5.15': dependencies: - '@swc/counter': 0.1.3 - tslib: 2.7.0 + tslib: 2.8.1 - '@t3-oss/env-core@0.11.1(typescript@5.7.2)(zod@3.24.1)': + '@t3-oss/env-core@0.11.1(typescript@5.7.3)(zod@3.24.1)': dependencies: zod: 3.24.1 optionalDependencies: - typescript: 5.7.2 + typescript: 5.7.3 - '@t3-oss/env-nextjs@0.11.1(typescript@5.7.2)(zod@3.24.1)': + '@t3-oss/env-nextjs@0.11.1(typescript@5.7.3)(zod@3.24.1)': dependencies: - '@t3-oss/env-core': 0.11.1(typescript@5.7.2)(zod@3.24.1) + '@t3-oss/env-core': 0.11.1(typescript@5.7.3)(zod@3.24.1) zod: 3.24.1 optionalDependencies: - typescript: 5.7.2 + typescript: 5.7.3 - '@tabler/icons-react@3.24.0(react@19.0.0)': + '@tabler/icons-react@3.28.1(react@19.0.0)': dependencies: - '@tabler/icons': 3.24.0 + '@tabler/icons': 3.28.1 react: 19.0.0 - '@tabler/icons@3.24.0': {} + '@tabler/icons@3.28.1': {} '@tanstack/match-sorter-utils@8.19.4': dependencies: remove-accents: 0.5.0 - '@tanstack/query-core@5.62.7': {} + '@tanstack/query-core@5.64.1': {} - '@tanstack/query-devtools@5.61.4': {} + '@tanstack/query-devtools@5.62.16': {} - '@tanstack/react-query-devtools@5.62.7(@tanstack/react-query@5.62.7(react@19.0.0))(react@19.0.0)': + '@tanstack/react-query-devtools@5.64.1(@tanstack/react-query@5.64.1(react@19.0.0))(react@19.0.0)': dependencies: - '@tanstack/query-devtools': 5.61.4 - '@tanstack/react-query': 5.62.7(react@19.0.0) + '@tanstack/query-devtools': 5.62.16 + '@tanstack/react-query': 5.64.1(react@19.0.0) react: 19.0.0 - '@tanstack/react-query-next-experimental@5.62.7(@tanstack/react-query@5.62.7(react@19.0.0))(next@14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0))(react@19.0.0)': + '@tanstack/react-query-next-experimental@5.64.1(@tanstack/react-query@5.64.1(react@19.0.0))(next@15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4))(react@19.0.0)': dependencies: - '@tanstack/react-query': 5.62.7(react@19.0.0) - next: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + '@tanstack/react-query': 5.64.1(react@19.0.0) + next: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) react: 19.0.0 - '@tanstack/react-query@5.62.7(react@19.0.0)': + '@tanstack/react-query@5.64.1(react@19.0.0)': dependencies: - '@tanstack/query-core': 5.62.7 + '@tanstack/query-core': 5.64.1 react: 19.0.0 '@tanstack/react-table@8.20.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': @@ -9936,15 +11756,15 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - '@tanstack/react-virtual@3.10.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@tanstack/react-virtual@3.11.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tanstack/virtual-core': 3.10.8 + '@tanstack/virtual-core': 3.11.2 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) '@tanstack/table-core@8.20.5': {} - '@tanstack/virtual-core@3.10.8': {} + '@tanstack/virtual-core@3.11.2': {} '@testcontainers/mysql@10.16.0': dependencies: @@ -9952,157 +11772,157 @@ snapshots: transitivePeerDependencies: - supports-color - '@tiptap/core@2.10.3(@tiptap/pm@2.10.3)': + '@tiptap/core@2.11.2(@tiptap/pm@2.11.2)': dependencies: - '@tiptap/pm': 2.10.3 + '@tiptap/pm': 2.11.2 - '@tiptap/extension-blockquote@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-blockquote@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-bold@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-bold@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-bubble-menu@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-bubble-menu@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 tippy.js: 6.3.7 - '@tiptap/extension-bullet-list@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-bullet-list@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-code-block@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-code-block@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 - '@tiptap/extension-code@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-code@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-color@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/extension-text-style@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)))': + '@tiptap/extension-color@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/extension-text-style@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/extension-text-style': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/extension-text-style': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) - '@tiptap/extension-document@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-document@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-dropcursor@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-dropcursor@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 - '@tiptap/extension-floating-menu@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-floating-menu@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 tippy.js: 6.3.7 - '@tiptap/extension-gapcursor@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-gapcursor@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 - '@tiptap/extension-hard-break@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-hard-break@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-heading@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-heading@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-highlight@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-highlight@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-history@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-history@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 - '@tiptap/extension-horizontal-rule@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-horizontal-rule@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 - '@tiptap/extension-image@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-image@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-italic@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-italic@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-link@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-link@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 - linkifyjs: 4.1.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + linkifyjs: 4.2.0 - '@tiptap/extension-list-item@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-list-item@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-ordered-list@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-ordered-list@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-paragraph@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-paragraph@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-strike@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-strike@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-table-cell@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-table-cell@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-table-header@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-table-header@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-table-row@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-table-row@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-table@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-table@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 - '@tiptap/extension-task-item@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)': + '@tiptap/extension-task-item@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 - '@tiptap/extension-task-list@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-task-list@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-text-align@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-text-align@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-text-style@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-text-style@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-text@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-text@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/extension-underline@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': + '@tiptap/extension-underline@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) - '@tiptap/pm@2.10.3': + '@tiptap/pm@2.11.2': dependencies: prosemirror-changeset: 2.2.1 prosemirror-collab: 1.3.1 @@ -10123,73 +11943,73 @@ snapshots: prosemirror-transform: 1.10.2 prosemirror-view: 1.37.0 - '@tiptap/react@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@tiptap/react@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/extension-bubble-menu': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-floating-menu': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/extension-bubble-menu': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-floating-menu': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 '@types/use-sync-external-store': 0.0.6 fast-deep-equal: 3.1.3 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) use-sync-external-store: 1.2.2(react@19.0.0) - '@tiptap/starter-kit@2.10.3': + '@tiptap/starter-kit@2.11.2': dependencies: - '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) - '@tiptap/extension-blockquote': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-bold': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-bullet-list': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-code': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-code-block': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-document': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-dropcursor': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-gapcursor': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-hard-break': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-heading': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-history': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-horizontal-rule': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3) - '@tiptap/extension-italic': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-list-item': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-ordered-list': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-paragraph': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-strike': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-text': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/extension-text-style': 2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3)) - '@tiptap/pm': 2.10.3 + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/extension-blockquote': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-bold': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-bullet-list': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-code': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-code-block': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-document': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-dropcursor': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-gapcursor': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-hard-break': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-heading': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-history': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-horizontal-rule': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-italic': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-list-item': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-ordered-list': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-paragraph': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-strike': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-text': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-text-style': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/pm': 2.11.2 '@tootallnate/quickjs-emscripten@0.23.0': {} - '@trpc/client@11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2)': + '@trpc/client@11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3)': dependencies: - '@trpc/server': 11.0.0-rc.660(typescript@5.7.2) - typescript: 5.7.2 + '@trpc/server': 11.0.0-rc.700(typescript@5.7.3) + typescript: 5.7.3 - '@trpc/next@11.0.0-rc.660(@tanstack/react-query@5.62.7(react@19.0.0))(@trpc/client@11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2))(@trpc/react-query@11.0.0-rc.660(@tanstack/react-query@5.62.7(react@19.0.0))(@trpc/client@11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.2))(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(next@14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.2)': + '@trpc/next@11.0.0-rc.700(@tanstack/react-query@5.64.1(react@19.0.0))(@trpc/client@11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3))(@trpc/react-query@11.0.0-rc.700(@tanstack/react-query@5.64.1(react@19.0.0))(@trpc/client@11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3))(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(next@15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': dependencies: - '@trpc/client': 11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2) - '@trpc/server': 11.0.0-rc.660(typescript@5.7.2) - next: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + '@trpc/client': 11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3) + '@trpc/server': 11.0.0-rc.700(typescript@5.7.3) + next: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - typescript: 5.7.2 + typescript: 5.7.3 optionalDependencies: - '@tanstack/react-query': 5.62.7(react@19.0.0) - '@trpc/react-query': 11.0.0-rc.660(@tanstack/react-query@5.62.7(react@19.0.0))(@trpc/client@11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.2) + '@tanstack/react-query': 5.64.1(react@19.0.0) + '@trpc/react-query': 11.0.0-rc.700(@tanstack/react-query@5.64.1(react@19.0.0))(@trpc/client@11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3))(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) - '@trpc/react-query@11.0.0-rc.660(@tanstack/react-query@5.62.7(react@19.0.0))(@trpc/client@11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2))(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.2)': + '@trpc/react-query@11.0.0-rc.700(@tanstack/react-query@5.64.1(react@19.0.0))(@trpc/client@11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3))(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': dependencies: - '@tanstack/react-query': 5.62.7(react@19.0.0) - '@trpc/client': 11.0.0-rc.660(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(typescript@5.7.2) - '@trpc/server': 11.0.0-rc.660(typescript@5.7.2) + '@tanstack/react-query': 5.64.1(react@19.0.0) + '@trpc/client': 11.0.0-rc.700(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(typescript@5.7.3) + '@trpc/server': 11.0.0-rc.700(typescript@5.7.3) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - typescript: 5.7.2 + typescript: 5.7.3 - '@trpc/server@11.0.0-rc.660(typescript@5.7.2)': + '@trpc/server@11.0.0-rc.700(typescript@5.7.3)': dependencies: - typescript: 5.7.2 + typescript: 5.7.3 '@tsconfig/node10@1.0.11': {} @@ -10201,7 +12021,7 @@ snapshots: '@tsconfig/svelte@1.0.13': {} - '@turbo/gen@2.3.3(@types/node@22.10.2)(typescript@5.7.2)': + '@turbo/gen@2.3.3(@types/node@22.10.7)(typescript@5.7.3)': dependencies: '@turbo/workspaces': 2.3.3 commander: 10.0.1 @@ -10211,7 +12031,7 @@ snapshots: node-plop: 0.26.3 picocolors: 1.0.1 proxy-agent: 6.4.0 - ts-node: 10.9.2(@types/node@22.10.2)(typescript@5.7.2) + ts-node: 10.9.2(@types/node@22.10.7)(typescript@5.7.3) update-check: 1.5.4 validate-npm-package-name: 5.0.1 transitivePeerDependencies: @@ -10235,9 +12055,15 @@ snapshots: semver: 7.6.2 update-check: 1.5.4 + '@types/adm-zip@0.5.7': + dependencies: + '@types/node': 22.10.7 + '@types/asn1@0.2.4': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 + + '@types/aws-lambda@8.10.146': {} '@types/babel__core@7.20.5': dependencies: @@ -10262,22 +12088,22 @@ snapshots: '@types/bcrypt@5.0.2': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/better-sqlite3@7.6.12': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.10.2 + '@types/node': 22.10.7 - '@types/chroma-js@2.4.4': {} + '@types/chroma-js@3.1.0': {} '@types/connect@3.4.38': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/cookie@0.4.1': {} @@ -10288,11 +12114,11 @@ snapshots: '@types/connect': 3.4.38 '@types/express': 4.17.21 '@types/keygrip': 1.0.6 - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/cors@2.8.17': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/css-font-loading-module@0.0.7': {} @@ -10300,13 +12126,13 @@ snapshots: '@types/docker-modem@3.0.6': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/ssh2': 1.15.1 - '@types/dockerode@3.3.32': + '@types/dockerode@3.3.34': dependencies: '@types/docker-modem': 3.0.6 - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/ssh2': 1.15.1 '@types/estree@1.0.5': {} @@ -10315,7 +12141,7 @@ snapshots: '@types/express-serve-static-core@4.19.5': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/qs': 6.9.16 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -10330,7 +12156,7 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/hast@2.3.10': dependencies: @@ -10368,14 +12194,13 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@22.10.2': + '@types/node@22.10.7': dependencies: undici-types: 6.20.0 - '@types/prismjs@1.26.5': {} + '@types/normalize-package-data@2.4.4': {} - '@types/prop-types@15.7.12': - optional: true + '@types/prismjs@1.26.5': {} '@types/qs@6.9.16': {} @@ -10385,38 +12210,34 @@ snapshots: '@types/range-parser@1.2.7': {} - '@types/react-dom@19.0.2(@types/react@19.0.1)': + '@types/react-dom@19.0.3(@types/react@19.0.7)': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.0.7 - '@types/react@18.3.13': - dependencies: - '@types/prop-types': 15.7.12 - csstype: 3.1.3 - optional: true - - '@types/react@19.0.1': + '@types/react@19.0.7': dependencies: csstype: 3.1.3 + '@types/semver@7.5.8': {} + '@types/send@0.17.4': dependencies: '@types/mime': 1.3.5 - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/send': 0.17.4 '@types/ssh2-streams@0.1.12': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/ssh2@0.5.52': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/ssh2-streams': 0.1.12 '@types/ssh2@1.15.1': @@ -10425,11 +12246,11 @@ snapshots: '@types/swagger-ui-react@4.18.3': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.0.7 '@types/through@0.0.33': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/tinycolor2@1.4.6': {} @@ -10445,87 +12266,87 @@ snapshots: '@types/ws@8.5.13': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@types/xml2js@0.4.14': dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 - '@typescript-eslint/eslint-plugin@8.18.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0)(typescript@5.7.2))(eslint@9.16.0)(typescript@5.7.2)': + '@typescript-eslint/eslint-plugin@8.20.0(@typescript-eslint/parser@8.20.0(eslint@9.18.0)(typescript@5.7.3))(eslint@9.18.0)(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.18.0(eslint@9.16.0)(typescript@5.7.2) - '@typescript-eslint/scope-manager': 8.18.0 - '@typescript-eslint/type-utils': 8.18.0(eslint@9.16.0)(typescript@5.7.2) - '@typescript-eslint/utils': 8.18.0(eslint@9.16.0)(typescript@5.7.2) - '@typescript-eslint/visitor-keys': 8.18.0 - eslint: 9.16.0 + '@typescript-eslint/parser': 8.20.0(eslint@9.18.0)(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.20.0 + '@typescript-eslint/type-utils': 8.20.0(eslint@9.18.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.20.0(eslint@9.18.0)(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.20.0 + eslint: 9.18.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.7.2) - typescript: 5.7.2 + ts-api-utils: 2.0.0(typescript@5.7.3) + typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.18.0(eslint@9.16.0)(typescript@5.7.2)': + '@typescript-eslint/parser@8.20.0(eslint@9.18.0)(typescript@5.7.3)': dependencies: - '@typescript-eslint/scope-manager': 8.18.0 - '@typescript-eslint/types': 8.18.0 - '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) - '@typescript-eslint/visitor-keys': 8.18.0 - debug: 4.3.7 - eslint: 9.16.0 - typescript: 5.7.2 + '@typescript-eslint/scope-manager': 8.20.0 + '@typescript-eslint/types': 8.20.0 + '@typescript-eslint/typescript-estree': 8.20.0(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.20.0 + debug: 4.4.0 + eslint: 9.18.0 + typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.18.0': + '@typescript-eslint/scope-manager@8.20.0': dependencies: - '@typescript-eslint/types': 8.18.0 - '@typescript-eslint/visitor-keys': 8.18.0 + '@typescript-eslint/types': 8.20.0 + '@typescript-eslint/visitor-keys': 8.20.0 - '@typescript-eslint/type-utils@8.18.0(eslint@9.16.0)(typescript@5.7.2)': + '@typescript-eslint/type-utils@8.20.0(eslint@9.18.0)(typescript@5.7.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) - '@typescript-eslint/utils': 8.18.0(eslint@9.16.0)(typescript@5.7.2) - debug: 4.3.7 - eslint: 9.16.0 - ts-api-utils: 1.3.0(typescript@5.7.2) - typescript: 5.7.2 + '@typescript-eslint/typescript-estree': 8.20.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.20.0(eslint@9.18.0)(typescript@5.7.3) + debug: 4.4.0 + eslint: 9.18.0 + ts-api-utils: 2.0.0(typescript@5.7.3) + typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.18.0': {} + '@typescript-eslint/types@8.20.0': {} - '@typescript-eslint/typescript-estree@8.18.0(typescript@5.7.2)': + '@typescript-eslint/typescript-estree@8.20.0(typescript@5.7.3)': dependencies: - '@typescript-eslint/types': 8.18.0 - '@typescript-eslint/visitor-keys': 8.18.0 - debug: 4.3.7 + '@typescript-eslint/types': 8.20.0 + '@typescript-eslint/visitor-keys': 8.20.0 + debug: 4.4.0 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.7.2) - typescript: 5.7.2 + ts-api-utils: 2.0.0(typescript@5.7.3) + typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.18.0(eslint@9.16.0)(typescript@5.7.2)': + '@typescript-eslint/utils@8.20.0(eslint@9.18.0)(typescript@5.7.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.16.0) - '@typescript-eslint/scope-manager': 8.18.0 - '@typescript-eslint/types': 8.18.0 - '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) - eslint: 9.16.0 - typescript: 5.7.2 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.18.0) + '@typescript-eslint/scope-manager': 8.20.0 + '@typescript-eslint/types': 8.20.0 + '@typescript-eslint/typescript-estree': 8.20.0(typescript@5.7.3) + eslint: 9.18.0 + typescript: 5.7.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.18.0': + '@typescript-eslint/visitor-keys@8.20.0': dependencies: - '@typescript-eslint/types': 8.18.0 + '@typescript-eslint/types': 8.20.0 eslint-visitor-keys: 4.2.0 '@umami/node@0.4.0': {} @@ -10558,14 +12379,14 @@ snapshots: global: 4.4.0 is-function: 1.0.2 - '@vitejs/plugin-react@4.3.4(vite@5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0))': + '@vitejs/plugin-react@4.3.4(vite@5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite: 5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) transitivePeerDependencies: - supports-color @@ -10583,7 +12404,7 @@ snapshots: std-env: 3.8.0 test-exclude: 7.0.1 tinyrainbow: 1.2.0 - vitest: 2.1.8(@types/node@22.10.2)(@vitest/ui@2.1.8)(jsdom@25.0.1)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vitest: 2.1.8(@types/node@22.10.7)(@vitest/ui@2.1.8)(jsdom@26.0.0)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) transitivePeerDependencies: - supports-color @@ -10594,13 +12415,13 @@ snapshots: chai: 5.1.2 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.8(vite@5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0))': + '@vitest/mocker@2.1.8(vite@5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0))': dependencies: '@vitest/spy': 2.1.8 estree-walker: 3.0.3 magic-string: 0.30.12 optionalDependencies: - vite: 5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite: 5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) '@vitest/pretty-format@2.1.8': dependencies: @@ -10630,7 +12451,7 @@ snapshots: sirv: 3.0.0 tinyglobby: 0.2.10 tinyrainbow: 1.2.0 - vitest: 2.1.8(@types/node@22.10.2)(@vitest/ui@2.1.8)(jsdom@25.0.1)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vitest: 2.1.8(@types/node@22.10.7)(@vitest/ui@2.1.8)(jsdom@26.0.0)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) '@vitest/utils@2.1.8': dependencies: @@ -10757,6 +12578,8 @@ snapshots: acorn@8.14.0: {} + adm-zip@0.5.16: {} + aes-decrypter@4.0.2: dependencies: '@babel/runtime': 7.25.6 @@ -10766,21 +12589,28 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.7 + debug: 4.4.0 transitivePeerDependencies: - supports-color agent-base@7.1.1: dependencies: - debug: 4.3.7 + debug: 4.4.0 transitivePeerDependencies: - supports-color + agent-base@7.1.3: {} + aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 indent-string: 4.0.0 + aggregate-error@5.0.0: + dependencies: + clean-stack: 5.2.0 + indent-string: 5.0.0 + ajv-keywords@3.5.2(ajv@6.12.6): dependencies: ajv: 6.12.6 @@ -10800,6 +12630,10 @@ snapshots: dependencies: type-fest: 0.21.3 + ansi-escapes@7.0.0: + dependencies: + environment: 1.1.0 + ansi-regex@5.0.1: {} ansi-regex@6.1.0: {} @@ -10814,6 +12648,8 @@ snapshots: ansi-styles@6.2.1: {} + any-promise@1.3.0: {} + apg-lite@1.0.4: {} aproba@2.0.0: {} @@ -10851,13 +12687,22 @@ snapshots: argparse@2.0.1: {} + argv-formatter@1.0.0: {} + aria-query@5.3.2: {} array-buffer-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 is-array-buffer: 3.0.4 + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.3 + is-array-buffer: 3.0.5 + + array-ify@1.0.0: {} + array-includes@3.1.8: dependencies: call-bind: 1.0.7 @@ -10871,9 +12716,9 @@ snapshots: array.prototype.findlast@1.2.5: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.7 es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 @@ -10901,25 +12746,42 @@ snapshots: es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.7 + es-shim-unscopables: 1.0.2 + array.prototype.tosorted@1.1.4: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.7 es-errors: 1.3.0 es-shim-unscopables: 1.0.2 arraybuffer.prototype.slice@1.0.3: dependencies: array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.7 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 + is-array-buffer: 3.0.5 + asn1@0.2.6: dependencies: safer-buffer: 2.1.2 @@ -10930,15 +12792,15 @@ snapshots: ast-types@0.13.4: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 ast-types@0.14.2: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 ast-types@0.16.1: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 async-lock@1.4.1: {} @@ -10948,7 +12810,7 @@ snapshots: autolinker@3.16.2: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 available-typed-arrays@1.0.7: dependencies: @@ -11020,9 +12882,11 @@ snapshots: - encoding - supports-color + before-after-hook@3.0.2: {} + bellajs@11.2.0: {} - better-sqlite3@11.7.0: + better-sqlite3@11.8.0: dependencies: bindings: 1.5.0 prebuild-install: 7.1.2 @@ -11039,6 +12903,8 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + bottleneck@2.19.5: {} + boxen@5.1.2: dependencies: ansi-align: 3.0.1 @@ -11097,6 +12963,11 @@ snapshots: cac@6.7.14: {} + call-bind-apply-helpers@1.0.1: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + call-bind@1.0.7: dependencies: es-define-property: 1.0.0 @@ -11105,6 +12976,18 @@ snapshots: get-intrinsic: 1.2.4 set-function-length: 1.2.2 + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.6 + set-function-length: 1.2.2 + + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.6 + callsites@3.1.0: {} camel-case@3.0.0: @@ -11142,6 +13025,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.3.0: {} + change-case@3.1.0: dependencies: camel-case: 3.0.0 @@ -11163,6 +13048,8 @@ snapshots: upper-case: 1.1.3 upper-case-first: 1.1.2 + char-regex@1.0.2: {} + character-entities-legacy@1.1.4: {} character-entities@1.2.4: {} @@ -11193,6 +13080,10 @@ snapshots: clean-stack@2.2.0: {} + clean-stack@5.2.0: + dependencies: + escape-string-regexp: 5.0.0 + cli-boxes@2.2.1: {} cli-cursor@3.1.0: @@ -11206,12 +13097,33 @@ snapshots: xycolors: 0.1.2 yargs: 17.7.2 + cli-highlight@2.1.11: + dependencies: + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.0 + cli-spinners@2.9.2: {} + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + cli-width@3.0.0: {} client-only@0.0.1: {} + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -11256,6 +13168,12 @@ snapshots: color-convert: 1.9.3 color-string: 1.9.1 + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + optional: true + colorspace@1.1.4: dependencies: color: 3.2.1 @@ -11271,6 +13189,11 @@ snapshots: commander@2.20.3: {} + compare-func@2.0.0: + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + compress-commons@6.0.2: dependencies: crc-32: 1.2.2 @@ -11281,7 +13204,7 @@ snapshots: concat-map@0.0.1: {} - concurrently@9.1.0: + concurrently@9.1.2: dependencies: chalk: 4.1.2 lodash: 4.17.21 @@ -11314,6 +13237,30 @@ snapshots: snake-case: 2.1.0 upper-case: 1.1.3 + conventional-changelog-angular@8.0.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-conventionalcommits@8.0.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-writer@8.0.0: + dependencies: + '@types/semver': 7.5.8 + conventional-commits-filter: 5.0.0 + handlebars: 4.7.8 + meow: 13.2.0 + semver: 7.6.3 + + conventional-commits-filter@5.0.0: {} + + conventional-commits-parser@6.0.0: + dependencies: + meow: 13.2.0 + + convert-hrtime@5.0.0: {} + convert-source-map@2.0.0: {} cookie-es@1.2.2: {} @@ -11322,7 +13269,7 @@ snapshots: cookie@0.7.2: {} - cookie@1.0.1: {} + cookie@1.0.2: {} cookies@0.9.1: dependencies: @@ -11346,6 +13293,15 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 + cosmiconfig@9.0.0(typescript@5.7.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.7.3 + cpu-features@0.0.10: dependencies: buildcheck: 0.0.6 @@ -11391,13 +13347,18 @@ snapshots: crypto-random-string@2.0.0: {} + crypto-random-string@4.0.0: + dependencies: + type-fest: 1.4.0 + css.escape@1.5.1: {} cssesc@3.0.0: {} - cssstyle@4.1.0: + cssstyle@4.2.1: dependencies: - rrweb-cssom: 0.7.1 + '@asamuzakjp/css-color': 2.8.2 + rrweb-cssom: 0.8.0 csstype@3.1.3: {} @@ -11408,26 +13369,44 @@ snapshots: data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 - whatwg-url: 14.0.0 + whatwg-url: 14.1.0 data-view-buffer@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + data-view-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + data-view-byte-offset@1.0.0: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-data-view: 1.0.1 + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dayjs@1.11.13: {} debug@3.2.7: @@ -11438,6 +13417,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.0: + dependencies: + ms: 2.1.3 + decimal.js@10.4.3: {} decompress-response@6.0.0: @@ -11460,7 +13443,7 @@ snapshots: dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 - gopd: 1.0.1 + gopd: 1.2.0 define-properties@1.2.1: dependencies: @@ -11524,16 +13507,16 @@ snapshots: docker-modem@3.0.8: dependencies: - debug: 4.3.7 + debug: 4.4.0 readable-stream: 3.6.2 split-ca: 1.0.1 ssh2: 1.16.0 transitivePeerDependencies: - supports-color - docker-modem@5.0.3: + docker-modem@5.0.5: dependencies: - debug: 4.3.7 + debug: 4.4.0 readable-stream: 3.6.2 split-ca: 1.0.1 ssh2: 1.16.0 @@ -11551,7 +13534,7 @@ snapshots: dockerode@4.0.2: dependencies: '@balena/dockerignore': 1.0.2 - docker-modem: 5.0.3 + docker-modem: 5.0.5 tar-fs: 2.0.1 transitivePeerDependencies: - supports-color @@ -11577,7 +13560,7 @@ snapshots: dependencies: is-obj: 2.0.0 - dotenv-cli@7.4.4: + dotenv-cli@8.0.0: dependencies: cross-spawn: 7.0.6 dotenv: 16.4.7 @@ -11592,7 +13575,7 @@ snapshots: drange@1.1.1: {} - drizzle-kit@0.30.1: + drizzle-kit@0.30.2: dependencies: '@drizzle-team/brocli': 0.10.2 '@esbuild-kit/esm-loader': 2.6.5 @@ -11601,20 +13584,30 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.38.1(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@19.0.1)(better-sqlite3@11.7.0)(mysql2@3.11.5)(react@19.0.0): + drizzle-orm@0.38.4(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@19.0.7)(better-sqlite3@11.8.0)(mysql2@3.12.0)(react@19.0.0): optionalDependencies: '@libsql/client-wasm': 0.14.0 '@types/better-sqlite3': 7.6.12 - '@types/react': 19.0.1 - better-sqlite3: 11.7.0 - mysql2: 3.11.5 + '@types/react': 19.0.7 + better-sqlite3: 11.8.0 + mysql2: 3.12.0 react: 19.0.0 - drizzle-zod@0.6.0(drizzle-orm@0.38.1(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@19.0.1)(better-sqlite3@11.7.0)(mysql2@3.11.5)(react@19.0.0))(zod@3.24.1): + drizzle-zod@0.6.1(drizzle-orm@0.38.4(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@19.0.7)(better-sqlite3@11.8.0)(mysql2@3.12.0)(react@19.0.0))(zod@3.24.1): dependencies: - drizzle-orm: 0.38.1(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@19.0.1)(better-sqlite3@11.7.0)(mysql2@3.11.5)(react@19.0.0) + drizzle-orm: 0.38.4(@libsql/client-wasm@0.14.0)(@types/better-sqlite3@7.6.12)(@types/react@19.0.7)(better-sqlite3@11.8.0)(mysql2@3.12.0)(react@19.0.0) zod: 3.24.1 + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer2@0.1.4: + dependencies: + readable-stream: 2.3.8 + eastasianwidth@0.2.0: {} effect@3.9.2: {} @@ -11625,6 +13618,8 @@ snapshots: emoji-regex@9.2.2: {} + emojilib@2.4.0: {} + emojis-list@3.0.0: {} enabled@2.0.0: {} @@ -11651,7 +13646,7 @@ snapshots: dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.17 - '@types/node': 22.10.2 + '@types/node': 22.10.7 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.7.2 @@ -11671,6 +13666,19 @@ snapshots: entities@4.5.0: {} + env-ci@11.1.0: + dependencies: + execa: 8.0.1 + java-properties: 1.0.2 + + env-paths@2.2.1: {} + + environment@1.1.0: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + es-abstract@1.23.3: dependencies: array-buffer-byte-length: 1.0.1 @@ -11720,28 +13728,82 @@ snapshots: unbox-primitive: 1.0.2 which-typed-array: 1.1.15 + es-abstract@1.23.7: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.2.6 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-regex: 1.2.1 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.0 + math-intrinsics: 1.1.0 + object-inspect: 1.13.3 + object-keys: 1.1.1 + object.assign: 4.1.7 + regexp.prototype.flags: 1.5.3 + safe-array-concat: 1.1.3 + safe-regex-test: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.18 + es-define-property@1.0.0: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 + + es-define-property@1.0.1: {} es-errors@1.3.0: {} - es-iterator-helpers@1.1.0: + es-iterator-helpers@1.2.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.7 es-errors: 1.3.0 es-set-tostringtag: 2.0.3 function-bind: 1.1.2 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 globalthis: 1.0.4 + gopd: 1.2.0 has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - internal-slot: 1.0.7 - iterator.prototype: 1.1.3 - safe-array-concat: 1.1.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.4 + safe-array-concat: 1.1.3 es-module-lexer@1.5.4: {} @@ -11751,7 +13813,7 @@ snapshots: es-set-tostringtag@2.0.3: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 has-tostringtag: 1.0.2 hasown: 2.0.2 @@ -11765,9 +13827,15 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + esbuild-register@3.6.0(esbuild@0.19.12): dependencies: - debug: 4.3.7 + debug: 4.4.0 esbuild: 0.19.12 transitivePeerDependencies: - supports-color @@ -11910,6 +13978,8 @@ snapshots: escape-string-regexp@4.0.0: {} + escape-string-regexp@5.0.0: {} + escodegen@2.1.0: dependencies: esprima: 4.0.1 @@ -11918,14 +13988,14 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-config-prettier@9.1.0(eslint@9.16.0): + eslint-config-prettier@10.0.1(eslint@9.18.0): dependencies: - eslint: 9.16.0 + eslint: 9.18.0 - eslint-config-turbo@2.3.3(eslint@9.16.0): + eslint-config-turbo@2.3.3(eslint@9.18.0): dependencies: - eslint: 9.16.0 - eslint-plugin-turbo: 2.3.3(eslint@9.16.0) + eslint: 9.18.0 + eslint-plugin-turbo: 2.3.3(eslint@9.18.0) eslint-import-resolver-node@0.3.9: dependencies: @@ -11935,17 +14005,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint@9.16.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.20.0(eslint@9.18.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.18.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.18.0(eslint@9.16.0)(typescript@5.7.2) - eslint: 9.16.0 + '@typescript-eslint/parser': 8.20.0(eslint@9.18.0)(typescript@5.7.3) + eslint: 9.18.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0)(typescript@5.7.2))(eslint@9.16.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.20.0(eslint@9.18.0)(typescript@5.7.3))(eslint@9.18.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -11954,9 +14024,9 @@ snapshots: array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.16.0 + eslint: 9.18.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint@9.16.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.20.0(eslint@9.18.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.18.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -11968,13 +14038,13 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.18.0(eslint@9.16.0)(typescript@5.7.2) + '@typescript-eslint/parser': 8.20.0(eslint@9.18.0)(typescript@5.7.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.16.0): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.18.0): dependencies: aria-query: 5.3.2 array-includes: 3.1.8 @@ -11984,7 +14054,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.16.0 + eslint: 9.18.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -11993,36 +14063,36 @@ snapshots: safe-regex-test: 1.0.3 string.prototype.includes: 2.0.1 - eslint-plugin-react-hooks@5.1.0(eslint@9.16.0): + eslint-plugin-react-hooks@5.1.0(eslint@9.18.0): dependencies: - eslint: 9.16.0 + eslint: 9.18.0 - eslint-plugin-react@7.37.2(eslint@9.16.0): + eslint-plugin-react@7.37.4(eslint@9.18.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 - array.prototype.flatmap: 1.3.2 + array.prototype.flatmap: 1.3.3 array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.1.0 - eslint: 9.16.0 + es-iterator-helpers: 1.2.1 + eslint: 9.18.0 estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 object.entries: 1.1.8 object.fromentries: 2.0.8 - object.values: 1.2.0 + object.values: 1.2.1 prop-types: 15.8.1 resolve: 2.0.0-next.5 semver: 6.3.1 - string.prototype.matchall: 4.0.11 + string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-turbo@2.3.3(eslint@9.16.0): + eslint-plugin-turbo@2.3.3(eslint@9.18.0): dependencies: dotenv: 16.0.3 - eslint: 9.16.0 + eslint: 9.18.0 eslint-scope@5.1.1: dependencies: @@ -12038,15 +14108,15 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.16.0: + eslint@9.18.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.16.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.18.0) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.19.0 - '@eslint/core': 0.9.0 + '@eslint/core': 0.10.0 '@eslint/eslintrc': 3.2.0 - '@eslint/js': 9.16.0 - '@eslint/plugin-kit': 0.2.3 + '@eslint/js': 9.18.0 + '@eslint/plugin-kit': 0.2.5 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.1 @@ -12055,7 +14125,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.3.7 + debug: 4.4.0 escape-string-regexp: 4.0.0 eslint-scope: 8.2.0 eslint-visitor-keys: 4.2.0 @@ -12121,6 +14191,33 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + execa@9.5.2: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.6 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.0 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 6.0.0 + pretty-ms: 9.2.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.1.1 + expand-template@2.0.3: {} expect-type@1.1.0: {} @@ -12131,10 +14228,20 @@ snapshots: iconv-lite: 0.4.24 tmp: 0.0.33 + fast-content-type-parse@2.0.1: {} + fast-deep-equal@3.1.3: {} fast-fifo@1.3.2: {} + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -12177,10 +14284,18 @@ snapshots: fflate@0.8.2: {} + figures@2.0.0: + dependencies: + escape-string-regexp: 1.0.5 + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 + figures@6.1.0: + dependencies: + is-unicode-supported: 2.1.0 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -12191,12 +14306,23 @@ snapshots: dependencies: to-regex-range: 5.0.1 + find-up-simple@1.0.0: {} + + find-up@2.1.0: + dependencies: + locate-path: 2.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - flag-icons@7.2.3: {} + find-versions@6.0.0: + dependencies: + semver-regex: 4.0.5 + super-regex: 1.0.0 + + flag-icons@7.3.1: {} flat-cache@4.0.1: dependencies: @@ -12224,8 +14350,19 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + format@0.2.2: {} + from2@2.3.0: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + fs-constants@1.0.0: {} fs-extra@10.1.0: @@ -12254,13 +14391,24 @@ snapshots: function-bind@1.1.2: {} + function-timeout@1.0.2: {} + function.prototype.name@1.1.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.7 functions-have-names: 1.2.3 + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + functions-have-names@1.2.3: {} gauge@3.0.2: @@ -12291,6 +14439,19 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.2 + get-intrinsic@1.2.6: + dependencies: + call-bind-apply-helpers: 1.0.1 + dunder-proto: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + function-bind: 1.1.2 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} get-port@5.1.1: {} @@ -12299,11 +14460,26 @@ snapshots: get-stream@6.0.1: {} + get-stream@7.0.1: {} + + get-stream@8.0.1: {} + + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + get-symbol-description@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 get-tsconfig@4.8.1: dependencies: @@ -12313,13 +14489,22 @@ snapshots: dependencies: basic-ftp: 5.0.5 data-uri-to-buffer: 6.0.2 - debug: 4.3.7 + debug: 4.4.0 fs-extra: 11.2.0 transitivePeerDependencies: - supports-color git-hooks-list@3.1.0: {} + git-log-parser@1.2.1: + dependencies: + argv-formatter: 1.0.0 + spawn-error-forwarder: 1.0.0 + split2: 1.0.0 + stream-combiner2: 1.1.1 + through2: 2.0.5 + traverse: 0.6.8 + github-from-package@0.0.0: {} glob-parent@5.1.2: @@ -12332,14 +14517,6 @@ snapshots: glob-to-regexp@0.4.1: {} - glob@10.3.10: - dependencies: - foreground-child: 3.3.0 - jackspeak: 2.3.6 - minimatch: 9.0.5 - minipass: 7.1.2 - path-scurry: 1.11.1 - glob@10.4.5: dependencies: foreground-child: 3.3.0 @@ -12349,7 +14526,7 @@ snapshots: package-json-from-dist: 1.0.0 path-scurry: 1.11.1 - glob@11.0.0: + glob@11.0.1: dependencies: foreground-child: 3.3.0 jackspeak: 4.0.1 @@ -12383,7 +14560,7 @@ snapshots: globalthis@1.0.4: dependencies: define-properties: 1.2.1 - gopd: 1.0.1 + gopd: 1.2.0 globby@10.0.2: dependencies: @@ -12396,11 +14573,22 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + globby@14.0.2: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.2 + ignore: 5.3.2 + path-type: 5.0.0 + slash: 5.1.0 + unicorn-magic: 0.1.0 + globrex@0.1.2: {} gopd@1.0.1: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.6 + + gopd@1.2.0: {} graceful-fs@4.2.10: {} @@ -12443,15 +14631,21 @@ snapshots: has-property-descriptors@1.0.2: dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 has-proto@1.0.3: {} + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + has-symbols@1.0.3: {} + has-symbols@1.1.0: {} + has-tostringtag@1.0.2: dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 has-unicode@2.0.1: {} @@ -12486,6 +14680,16 @@ snapshots: hono@4.6.1: {} + hook-std@3.0.0: {} + + hosted-git-info@7.0.2: + dependencies: + lru-cache: 10.4.3 + + hosted-git-info@8.0.2: + dependencies: + lru-cache: 10.4.3 + html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 @@ -12505,26 +14709,37 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.1 - debug: 4.3.7 + debug: 4.4.0 transitivePeerDependencies: - supports-color https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.7 + debug: 4.4.0 transitivePeerDependencies: - supports-color https-proxy-agent@7.0.5: dependencies: agent-base: 7.1.1 - debug: 4.3.7 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 transitivePeerDependencies: - supports-color human-signals@2.1.0: {} + human-signals@5.0.0: {} + + human-signals@8.0.0: {} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -12546,12 +14761,25 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + import-from-esm@2.0.0: + dependencies: + debug: 4.4.0 + import-meta-resolve: 4.1.0 + transitivePeerDependencies: + - supports-color + import-lazy@2.1.0: {} + import-meta-resolve@4.1.0: {} + imurmurhash@0.1.4: {} indent-string@4.0.0: {} + indent-string@5.0.0: {} + + index-to-position@0.1.2: {} + inflation@2.1.0: {} inflight@1.0.6: @@ -12603,24 +14831,35 @@ snapshots: dependencies: es-errors: 1.3.0 hasown: 2.0.2 - side-channel: 1.0.6 + side-channel: 1.1.0 + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 intl-messageformat@10.7.1: dependencies: '@formatjs/ecma402-abstract': 2.2.0 '@formatjs/fast-memoize': 2.2.1 '@formatjs/icu-messageformat-parser': 2.8.0 - tslib: 2.7.0 + tslib: 2.8.1 + + into-stream@7.0.0: + dependencies: + from2: 2.3.0 + p-is-promise: 3.0.0 invariant@2.2.4: dependencies: loose-envify: 1.4.0 - ioredis@5.4.1: + ioredis@5.4.2: dependencies: '@ioredis/commands': 1.2.0 cluster-key-slot: 1.1.2 - debug: 4.3.7 + debug: 4.4.0 denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -12646,8 +14885,16 @@ snapshots: is-array-buffer@3.0.4: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bind: 1.0.8 + get-intrinsic: 1.2.6 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.2.6 + + is-arrayish@0.2.1: {} is-arrayish@0.3.2: {} @@ -12659,9 +14906,18 @@ snapshots: dependencies: has-bigints: 1.0.2 + is-bigint@1.1.0: + dependencies: + has-bigints: 1.0.2 + is-boolean-object@1.1.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + has-tostringtag: 1.0.2 + + is-boolean-object@1.2.1: + dependencies: + call-bound: 1.0.3 has-tostringtag: 1.0.2 is-callable@1.2.7: {} @@ -12678,17 +14934,28 @@ snapshots: dependencies: is-typed-array: 1.1.13 + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.3 + get-intrinsic: 1.2.6 + is-typed-array: 1.1.15 + is-date-object@1.0.5: dependencies: has-tostringtag: 1.0.2 + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + is-decimal@1.0.4: {} is-extglob@2.1.1: {} - is-finalizationregistry@1.0.2: + is-finalizationregistry@1.1.1: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.3 is-fullwidth-code-point@3.0.0: {} @@ -12725,6 +14992,11 @@ snapshots: dependencies: has-tostringtag: 1.0.2 + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + is-number@7.0.0: {} is-obj@2.0.0: {} @@ -12744,30 +15016,62 @@ snapshots: call-bind: 1.0.7 has-tostringtag: 1.0.2 + is-regex@1.2.1: + dependencies: + call-bound: 1.0.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + is-set@2.0.3: {} is-shared-array-buffer@1.0.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.3 is-stream@2.0.1: {} + is-stream@3.0.0: {} + + is-stream@4.0.1: {} + is-string@1.0.7: dependencies: has-tostringtag: 1.0.2 + is-string@1.1.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + is-symbol@1.0.4: dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.3 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 is-typed-array@1.1.13: dependencies: which-typed-array: 1.1.15 + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.18 + is-typedarray@1.0.0: {} is-unicode-supported@0.1.0: {} + is-unicode-supported@2.1.0: {} + is-upper-case@1.1.2: dependencies: upper-case: 1.1.3 @@ -12776,12 +15080,16 @@ snapshots: is-weakref@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + + is-weakref@1.1.0: + dependencies: + call-bound: 1.0.3 is-weakset@2.0.3: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bind: 1.0.8 + get-intrinsic: 1.2.6 is-what@4.1.16: {} @@ -12802,6 +15110,14 @@ snapshots: transitivePeerDependencies: - encoding + issue-parser@7.0.1: + dependencies: + lodash.capitalize: 4.2.1 + lodash.escaperegexp: 4.1.2 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.uniqby: 4.7.0 + istanbul-lib-coverage@3.2.2: {} istanbul-lib-report@3.0.1: @@ -12813,7 +15129,7 @@ snapshots: istanbul-lib-source-maps@5.0.6: dependencies: '@jridgewell/trace-mapping': 0.3.25 - debug: 4.3.7 + debug: 4.4.0 istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -12823,20 +15139,15 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - iterator.prototype@1.1.3: + iterator.prototype@1.1.4: dependencies: - define-properties: 1.2.1 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.6 + define-data-property: 1.1.4 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.6 + has-symbols: 1.1.0 + reflect.getprototypeof: 1.0.9 set-function-name: 2.0.2 - jackspeak@2.3.6: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 @@ -12849,9 +15160,11 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + java-properties@1.0.2: {} + jest-worker@27.5.1: dependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -12859,14 +15172,9 @@ snapshots: jose@5.9.6: {} - jotai@2.10.3(@types/react@18.3.13)(react@19.0.0): + jotai@2.11.0(@types/react@19.0.7)(react@19.0.0): optionalDependencies: - '@types/react': 18.3.13 - react: 19.0.0 - - jotai@2.10.3(@types/react@19.0.1)(react@19.0.0): - optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.0.7 react: 19.0.0 js-base64@3.7.7: @@ -12882,19 +15190,19 @@ snapshots: jsbn@1.1.0: {} - jsdom@25.0.1: + jsdom@26.0.0: dependencies: - cssstyle: 4.1.0 + cssstyle: 4.2.1 data-urls: 5.0.0 decimal.js: 10.4.3 - form-data: 4.0.0 + form-data: 4.0.1 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.5 + https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.12 - parse5: 7.1.2 - rrweb-cssom: 0.7.1 + nwsapi: 2.2.16 + parse5: 7.2.1 + rrweb-cssom: 0.8.0 saxes: 6.0.0 symbol-tree: 3.2.4 tough-cookie: 5.0.0 @@ -12902,7 +15210,7 @@ snapshots: webidl-conversions: 7.0.0 whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 - whatwg-url: 14.0.0 + whatwg-url: 14.1.0 ws: 8.18.0 xml-name-validator: 5.0.0 transitivePeerDependencies: @@ -12914,6 +15222,8 @@ snapshots: json-buffer@3.0.1: {} + json-parse-better-errors@1.0.2: {} + json-parse-even-better-errors@2.3.1: {} json-schema-traverse@0.4.1: {} @@ -12963,14 +15273,14 @@ snapshots: dependencies: readable-stream: 2.3.8 - ldapts@7.2.2: + ldapts@7.3.1: dependencies: '@types/asn1': 0.2.4 asn1: 0.2.6 - debug: 4.3.7 + debug: 4.4.0 strict-event-emitter-types: 2.0.0 - uuid: 11.0.3 - whatwg-url: 14.0.0 + uuid: 11.0.4 + whatwg-url: 14.1.0 transitivePeerDependencies: - supports-color @@ -12979,11 +15289,20 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lines-and-columns@1.2.4: {} + linkify-it@5.0.0: dependencies: uc.micro: 2.1.0 - linkifyjs@4.1.3: {} + linkifyjs@4.2.0: {} + + load-json-file@4.0.0: + dependencies: + graceful-fs: 4.2.11 + parse-json: 4.0.0 + pify: 3.0.0 + strip-bom: 3.0.0 loader-runner@4.3.0: {} @@ -12993,22 +15312,39 @@ snapshots: emojis-list: 3.0.0 json5: 2.2.3 + locate-path@2.0.0: + dependencies: + p-locate: 2.0.0 + path-exists: 3.0.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 + lodash-es@4.17.21: {} + + lodash.capitalize@4.2.1: {} + lodash.clonedeep@4.5.0: {} lodash.debounce@4.0.8: {} lodash.defaults@4.2.0: {} + lodash.escaperegexp@4.1.2: {} + lodash.get@4.4.2: {} lodash.isarguments@3.1.0: {} + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + lodash.merge@4.6.2: {} + lodash.uniqby@4.7.0: {} + lodash@4.17.21: {} log-symbols@3.0.0: @@ -13050,7 +15386,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.0.1: {} + lru-cache@11.0.2: {} lru-cache@5.1.1: dependencies: @@ -13086,29 +15422,15 @@ snapshots: make-error@1.3.6: {} - mantine-react-table@2.0.0-beta.7(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/dates@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(@tabler/icons-react@3.24.0(react@19.0.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + mantine-react-table@2.0.0-beta.8(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/dates@7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(@tabler/icons-react@3.28.1(react@19.0.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: - '@mantine/core': 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/dates': 7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@18.3.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/hooks': 7.15.1(react@19.0.0) - '@tabler/icons-react': 3.24.0(react@19.0.0) + '@mantine/core': 7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/dates': 7.16.0(@mantine/core@7.16.0(@mantine/hooks@7.16.0(react@19.0.0))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.16.0(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@mantine/hooks': 7.16.0(react@19.0.0) + '@tabler/icons-react': 3.28.1(react@19.0.0) '@tanstack/match-sorter-utils': 8.19.4 '@tanstack/react-table': 8.20.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tanstack/react-virtual': 3.10.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - clsx: 2.1.1 - dayjs: 1.11.13 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - - mantine-react-table@2.0.0-beta.7(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/dates@7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(@tabler/icons-react@3.24.0(react@19.0.0))(clsx@2.1.1)(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@mantine/core': 7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/dates': 7.15.1(@mantine/core@7.15.1(@mantine/hooks@7.15.1(react@19.0.0))(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@mantine/hooks@7.15.1(react@19.0.0))(dayjs@1.11.13)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@mantine/hooks': 7.15.1(react@19.0.0) - '@tabler/icons-react': 3.24.0(react@19.0.0) - '@tanstack/match-sorter-utils': 8.19.4 - '@tanstack/react-table': 8.20.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@tanstack/react-virtual': 3.10.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@tanstack/react-virtual': 3.11.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) clsx: 2.1.1 dayjs: 1.11.13 react: 19.0.0 @@ -13123,10 +15445,27 @@ snapshots: punycode.js: 2.3.1 uc.micro: 2.1.0 + marked-terminal@7.2.1(marked@12.0.2): + dependencies: + ansi-escapes: 7.0.0 + ansi-regex: 6.1.0 + chalk: 5.3.0 + cli-highlight: 2.1.11 + cli-table3: 0.6.5 + marked: 12.0.2 + node-emoji: 2.2.0 + supports-hyperlinks: 3.1.0 + + marked@12.0.2: {} + + math-intrinsics@1.1.0: {} + mdurl@2.0.0: {} media-typer@0.3.0: {} + meow@13.2.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -13144,8 +15483,12 @@ snapshots: mime@3.0.0: {} + mime@4.0.4: {} + mimic-fn@2.1.0: {} + mimic-fn@4.0.0: {} + mimic-response@3.1.0: {} min-document@2.19.0: @@ -13221,7 +15564,7 @@ snapshots: '@babel/runtime': 7.25.6 global: 4.4.0 - mysql2@3.11.5: + mysql2@3.12.0: dependencies: aws-ssl-profiles: 1.1.2 denque: 2.1.0 @@ -13233,6 +15576,12 @@ snapshots: seq-queue: 0.0.5 sqlstring: 2.3.3 + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + named-placeholders@1.1.3: dependencies: lru-cache: 7.18.3 @@ -13256,44 +15605,47 @@ snapshots: neotraverse@0.6.18: {} + nerf-dart@1.0.0: {} + netmask@2.0.2: {} - next-auth@5.0.0-beta.25(next@14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0))(react@19.0.0): + next-auth@5.0.0-beta.25(next@15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4))(react@19.0.0): dependencies: '@auth/core': 0.37.2 - next: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + next: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) react: 19.0.0 - next-intl@3.26.1(next@14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0))(react@19.0.0): + next-intl@3.26.3(next@15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4))(react@19.0.0): dependencies: '@formatjs/intl-localematcher': 0.5.5 negotiator: 1.0.0 - next: 14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0) + next: 15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4) react: 19.0.0 - use-intl: 3.26.1(react@19.0.0) + use-intl: 3.26.3(react@19.0.0) - next@14.2.20(@babel/core@7.26.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.0): + next@15.1.4(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.83.4): dependencies: - '@next/env': 14.2.20 - '@swc/helpers': 0.5.5 + '@next/env': 15.1.4 + '@swc/counter': 0.1.3 + '@swc/helpers': 0.5.15 busboy: 1.6.0 caniuse-lite: 1.0.30001679 - graceful-fs: 4.2.11 postcss: 8.4.31 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.1(@babel/core@7.26.0)(react@19.0.0) + styled-jsx: 5.1.6(@babel/core@7.26.0)(react@19.0.0) optionalDependencies: - '@next/swc-darwin-arm64': 14.2.20 - '@next/swc-darwin-x64': 14.2.20 - '@next/swc-linux-arm64-gnu': 14.2.20 - '@next/swc-linux-arm64-musl': 14.2.20 - '@next/swc-linux-x64-gnu': 14.2.20 - '@next/swc-linux-x64-musl': 14.2.20 - '@next/swc-win32-arm64-msvc': 14.2.20 - '@next/swc-win32-ia32-msvc': 14.2.20 - '@next/swc-win32-x64-msvc': 14.2.20 - sass: 1.83.0 + '@next/swc-darwin-arm64': 15.1.4 + '@next/swc-darwin-x64': 15.1.4 + '@next/swc-linux-arm64-gnu': 15.1.4 + '@next/swc-linux-arm64-musl': 15.1.4 + '@next/swc-linux-x64-gnu': 15.1.4 + '@next/swc-linux-x64-musl': 15.1.4 + '@next/swc-win32-arm64-msvc': 15.1.4 + '@next/swc-win32-x64-msvc': 15.1.4 + '@playwright/test': 1.49.1 + sass: 1.83.4 + sharp: 0.33.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -13328,6 +15680,13 @@ snapshots: node-domexception@1.0.0: {} + node-emoji@2.2.0: + dependencies: + '@sindresorhus/is': 4.6.0 + char-regex: 1.0.2 + emojilib: 2.4.0 + skin-tone: 2.0.0 + node-fetch-commonjs@3.3.2: dependencies: node-domexception: 1.0.0 @@ -13367,12 +15726,31 @@ snapshots: dependencies: abbrev: 1.1.1 + normalize-package-data@6.0.2: + dependencies: + hosted-git-info: 7.0.2 + semver: 7.6.3 + validate-npm-package-license: 3.0.4 + normalize-path@3.0.0: {} + normalize-url@8.0.1: {} + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 + + npm@10.9.2: {} + npmlog@5.0.1: dependencies: are-we-there-yet: 2.0.0 @@ -13380,7 +15758,7 @@ snapshots: gauge: 3.0.2 set-blocking: 2.0.0 - nwsapi@2.2.12: {} + nwsapi@2.2.16: {} oauth4webapi@3.0.0: {} @@ -13390,6 +15768,8 @@ snapshots: object-inspect@1.13.2: {} + object-inspect@1.13.3: {} + object-keys@1.1.1: {} object.assign@4.1.5: @@ -13399,9 +15779,18 @@ snapshots: has-symbols: 1.0.3 object-keys: 1.1.1 + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + has-symbols: 1.1.0 + object-keys: 1.1.1 + object.entries@1.1.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-object-atoms: 1.0.0 @@ -13424,6 +15813,26 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + octokit@4.1.0: + dependencies: + '@octokit/app': 15.1.2 + '@octokit/core': 6.1.3 + '@octokit/oauth-app': 7.1.5 + '@octokit/plugin-paginate-graphql': 5.2.4(@octokit/core@6.1.3) + '@octokit/plugin-paginate-rest': 11.4.0(@octokit/core@6.1.3) + '@octokit/plugin-rest-endpoint-methods': 13.3.0(@octokit/core@6.1.3) + '@octokit/plugin-retry': 7.1.3(@octokit/core@6.1.3) + '@octokit/plugin-throttling': 9.4.0(@octokit/core@6.1.3) + '@octokit/request-error': 6.1.6 + '@octokit/types': 13.7.0 + ofetch@1.4.1: dependencies: destr: 2.0.3 @@ -13444,6 +15853,10 @@ snapshots: dependencies: mimic-fn: 2.1.0 + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + openapi-path-templating@1.6.0: dependencies: apg-lite: 1.0.4 @@ -13452,7 +15865,7 @@ snapshots: dependencies: apg-lite: 1.0.4 - openapi3-ts@4.3.3: + openapi3-ts@4.4.0: dependencies: yaml: 2.5.1 @@ -13492,10 +15905,26 @@ snapshots: os-tmpdir@1.0.2: {} + p-each-series@3.0.0: {} + + p-filter@4.1.0: + dependencies: + p-map: 7.0.3 + + p-is-promise@3.0.0: {} + + p-limit@1.3.0: + dependencies: + p-try: 1.0.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@2.0.0: + dependencies: + p-limit: 1.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 @@ -13504,11 +15933,19 @@ snapshots: dependencies: aggregate-error: 3.1.0 + p-map@7.0.3: {} + + p-reduce@2.1.0: {} + + p-reduce@3.0.0: {} + + p-try@1.0.0: {} + pac-proxy-agent@7.0.2: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.1 - debug: 4.3.7 + debug: 4.4.0 get-uri: 6.0.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 @@ -13543,9 +15980,37 @@ snapshots: is-decimal: 1.0.4 is-hexadecimal: 1.0.4 + parse-json@4.0.0: + dependencies: + error-ex: 1.3.2 + json-parse-better-errors: 1.0.2 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-json@8.1.0: + dependencies: + '@babel/code-frame': 7.26.2 + index-to-position: 0.1.2 + type-fest: 4.30.2 + parse-ms@3.0.0: {} - parse5@7.1.2: + parse-ms@4.0.0: {} + + parse5-htmlparser2-tree-adapter@6.0.1: + dependencies: + parse5: 6.0.1 + + parse5@5.1.1: {} + + parse5@6.0.1: {} + + parse5@7.2.1: dependencies: entities: 4.5.0 @@ -13558,12 +16023,16 @@ snapshots: dependencies: no-case: 2.3.2 + path-exists@3.0.0: {} + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} path-key@3.1.1: {} + path-key@4.0.0: {} + path-parse@1.0.7: {} path-scurry@1.11.1: @@ -13573,11 +16042,13 @@ snapshots: path-scurry@2.0.0: dependencies: - lru-cache: 11.0.1 + lru-cache: 11.0.2 minipass: 7.1.2 path-type@4.0.0: {} + path-type@5.0.0: {} + pathe@1.1.2: {} pathval@2.0.0: {} @@ -13590,6 +16061,8 @@ snapshots: picomatch@4.0.2: {} + pify@3.0.0: {} + piscina@4.6.1: optionalDependencies: nice-napi: 1.0.2 @@ -13598,14 +16071,29 @@ snapshots: dependencies: '@babel/runtime': 7.25.6 + pkg-conf@2.1.0: + dependencies: + find-up: 2.1.0 + load-json-file: 4.0.0 + playwright-core@1.49.0: {} + playwright-core@1.49.1: + optional: true + playwright@1.49.0: dependencies: playwright-core: 1.49.0 optionalDependencies: fsevents: 2.3.2 + playwright@1.49.1: + dependencies: + playwright-core: 1.49.1 + optionalDependencies: + fsevents: 2.3.2 + optional: true + possible-typed-array-names@1.0.0: {} postcss-js@4.0.1(postcss@8.4.47): @@ -13683,9 +16171,9 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-packagejson@2.5.6(prettier@3.4.2): + prettier-plugin-packagejson@2.5.8(prettier@3.4.2): dependencies: - sort-package-json: 2.12.0 + sort-package-json: 2.14.0 synckit: 0.9.2 optionalDependencies: prettier: 3.4.2 @@ -13698,6 +16186,10 @@ snapshots: dependencies: parse-ms: 3.0.0 + pretty-ms@9.2.0: + dependencies: + parse-ms: 4.0.0 + pretty-print-error@1.1.2(patch_hash=4arrfgbz7em6s4gqywse7esg4u): dependencies: kleur: 4.1.5 @@ -13835,10 +16327,14 @@ snapshots: proto-list@1.2.4: {} + proxmox-api@1.1.1: + dependencies: + undici: 7.2.3 + proxy-agent@6.4.0: dependencies: agent-base: 7.1.1 - debug: 4.3.7 + debug: 4.4.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 lru-cache: 7.18.3 @@ -13865,7 +16361,7 @@ snapshots: qs@6.13.1: dependencies: - side-channel: 1.0.6 + side-channel: 1.1.0 querystringify@2.2.0: {} @@ -13921,7 +16417,12 @@ snapshots: react: 19.0.0 scheduler: 0.25.0 - react-error-boundary@4.1.2(react@19.0.0): + react-dropzone-esm@15.2.0(react@19.0.0): + dependencies: + prop-types: 15.8.1 + react: 19.0.0 + + react-error-boundary@5.0.0(react@19.0.0): dependencies: '@babel/runtime': 7.25.6 react: 19.0.0 @@ -13943,59 +16444,40 @@ snapshots: react-is@16.13.1: {} - react-number-format@5.4.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-number-format@5.4.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - react-redux@9.1.2(@types/react@19.0.1)(react@19.0.0)(redux@5.0.1): + react-redux@9.1.2(@types/react@19.0.7)(react@19.0.0)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.3 react: 19.0.0 use-sync-external-store: 1.2.2(react@19.0.0) optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.0.7 redux: 5.0.1 react-refresh@0.14.2: {} - react-remove-scroll-bar@2.3.6(@types/react@18.3.13)(react@19.0.0): + react-remove-scroll-bar@2.3.8(@types/react@19.0.7)(react@19.0.0): dependencies: react: 19.0.0 - react-style-singleton: 2.2.1(@types/react@18.3.13)(react@19.0.0) - tslib: 2.7.0 + react-style-singleton: 2.2.3(@types/react@19.0.7)(react@19.0.0) + tslib: 2.8.1 optionalDependencies: - '@types/react': 18.3.13 + '@types/react': 19.0.7 - react-remove-scroll-bar@2.3.6(@types/react@19.0.1)(react@19.0.0): + react-remove-scroll@2.6.2(@types/react@19.0.7)(react@19.0.0): dependencies: react: 19.0.0 - react-style-singleton: 2.2.1(@types/react@19.0.1)(react@19.0.0) - tslib: 2.7.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.0.7)(react@19.0.0) + react-style-singleton: 2.2.3(@types/react@19.0.7)(react@19.0.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.0.7)(react@19.0.0) + use-sidecar: 1.1.2(@types/react@19.0.7)(react@19.0.0) optionalDependencies: - '@types/react': 19.0.1 - - react-remove-scroll@2.6.0(@types/react@18.3.13)(react@19.0.0): - dependencies: - react: 19.0.0 - react-remove-scroll-bar: 2.3.6(@types/react@18.3.13)(react@19.0.0) - react-style-singleton: 2.2.1(@types/react@18.3.13)(react@19.0.0) - tslib: 2.7.0 - use-callback-ref: 1.3.2(@types/react@18.3.13)(react@19.0.0) - use-sidecar: 1.1.2(@types/react@18.3.13)(react@19.0.0) - optionalDependencies: - '@types/react': 18.3.13 - - react-remove-scroll@2.6.0(@types/react@19.0.1)(react@19.0.0): - dependencies: - react: 19.0.0 - react-remove-scroll-bar: 2.3.6(@types/react@19.0.1)(react@19.0.0) - react-style-singleton: 2.2.1(@types/react@19.0.1)(react@19.0.0) - tslib: 2.7.0 - use-callback-ref: 1.3.2(@types/react@19.0.1)(react@19.0.0) - use-sidecar: 1.1.2(@types/react@19.0.1)(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.0.7 react-scan@0.0.31: dependencies: @@ -14010,23 +16492,13 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - react-style-singleton@2.2.1(@types/react@18.3.13)(react@19.0.0): + react-style-singleton@2.2.3(@types/react@19.0.7)(react@19.0.0): dependencies: get-nonce: 1.0.1 - invariant: 2.2.4 react: 19.0.0 - tslib: 2.7.0 + tslib: 2.8.1 optionalDependencies: - '@types/react': 18.3.13 - - react-style-singleton@2.2.1(@types/react@19.0.1)(react@19.0.0): - dependencies: - get-nonce: 1.0.1 - invariant: 2.2.4 - react: 19.0.0 - tslib: 2.7.0 - optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.0.7 react-syntax-highlighter@15.5.0(react@19.0.0): dependencies: @@ -14037,21 +16509,12 @@ snapshots: react: 19.0.0 refractor: 3.6.0 - react-textarea-autosize@8.5.5(@types/react@18.3.13)(react@19.0.0): + react-textarea-autosize@8.5.6(@types/react@19.0.7)(react@19.0.0): dependencies: '@babel/runtime': 7.25.6 react: 19.0.0 use-composed-ref: 1.3.0(react@19.0.0) - use-latest: 1.2.1(@types/react@18.3.13)(react@19.0.0) - transitivePeerDependencies: - - '@types/react' - - react-textarea-autosize@8.5.5(@types/react@19.0.1)(react@19.0.0): - dependencies: - '@babel/runtime': 7.25.6 - react: 19.0.0 - use-composed-ref: 1.3.0(react@19.0.0) - use-latest: 1.2.1(@types/react@19.0.1)(react@19.0.0) + use-latest: 1.2.1(@types/react@19.0.7)(react@19.0.0) transitivePeerDependencies: - '@types/react' @@ -14066,6 +16529,20 @@ snapshots: react@19.0.0: {} + read-package-up@11.0.0: + dependencies: + find-up-simple: 1.0.0 + read-pkg: 9.0.1 + type-fest: 4.30.2 + + read-pkg@9.0.1: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 6.0.2 + parse-json: 8.1.0 + type-fest: 4.30.2 + unicorn-magic: 0.1.0 + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -14102,7 +16579,7 @@ snapshots: esprima: 4.0.1 source-map: 0.6.1 tiny-invariant: 1.3.3 - tslib: 2.7.0 + tslib: 2.8.1 redis-errors@1.2.0: {} @@ -14116,15 +16593,16 @@ snapshots: redux@5.0.1: {} - reflect.getprototypeof@1.0.6: + reflect.getprototypeof@1.0.9: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + dunder-proto: 1.0.1 + es-abstract: 1.23.7 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - globalthis: 1.0.4 - which-builtin-type: 1.1.4 + get-intrinsic: 1.2.6 + gopd: 1.2.0 + which-builtin-type: 1.2.1 refractor@3.6.0: dependencies: @@ -14136,7 +16614,14 @@ snapshots: regexp.prototype.flags@1.5.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + + regexp.prototype.flags@1.5.3: + dependencies: + call-bind: 1.0.8 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 @@ -14175,6 +16660,8 @@ snapshots: resolve-from@4.0.0: {} + resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} resolve@1.22.8: @@ -14234,7 +16721,7 @@ snapshots: dependencies: rrweb-snapshot: 2.0.0-alpha.4 - rrweb-cssom@0.7.1: {} + rrweb-cssom@0.8.0: {} rrweb-player@1.0.0-alpha.4: dependencies: @@ -14274,9 +16761,17 @@ snapshots: safe-array-concat@1.1.2: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 + call-bind: 1.0.8 + get-intrinsic: 1.2.6 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.2.6 + has-symbols: 1.1.0 isarray: 2.0.5 safe-buffer@5.1.2: {} @@ -14289,11 +16784,17 @@ snapshots: es-errors: 1.3.0 is-regex: 1.1.4 + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-regex: 1.2.1 + safe-stable-stringify@2.5.0: {} safer-buffer@2.1.2: {} - sass@1.83.0: + sass@1.83.4: dependencies: chokidar: 4.0.0 immutable: 5.0.2 @@ -14315,10 +16816,53 @@ snapshots: ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) + semantic-release@24.2.1(typescript@5.7.3): + dependencies: + '@semantic-release/commit-analyzer': 13.0.1(semantic-release@24.2.1(typescript@5.7.3)) + '@semantic-release/error': 4.0.0 + '@semantic-release/github': 11.0.1(semantic-release@24.2.1(typescript@5.7.3)) + '@semantic-release/npm': 12.0.1(semantic-release@24.2.1(typescript@5.7.3)) + '@semantic-release/release-notes-generator': 14.0.3(semantic-release@24.2.1(typescript@5.7.3)) + aggregate-error: 5.0.0 + cosmiconfig: 9.0.0(typescript@5.7.3) + debug: 4.4.0 + env-ci: 11.1.0 + execa: 9.5.2 + figures: 6.1.0 + find-versions: 6.0.0 + get-stream: 6.0.1 + git-log-parser: 1.2.1 + hook-std: 3.0.0 + hosted-git-info: 8.0.2 + import-from-esm: 2.0.0 + lodash-es: 4.17.21 + marked: 12.0.2 + marked-terminal: 7.2.1(marked@12.0.2) + micromatch: 4.0.8 + p-each-series: 3.0.0 + p-reduce: 3.0.0 + read-package-up: 11.0.0 + resolve-from: 5.0.0 + semver: 7.6.3 + semver-diff: 4.0.0 + signale: 1.4.0 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + - typescript + semver-diff@3.1.1: dependencies: semver: 6.3.1 + semver-diff@4.0.0: + dependencies: + semver: 7.6.3 + + semver-parser@4.1.7: {} + + semver-regex@4.0.5: {} + semver@6.3.1: {} semver@7.6.2: {} @@ -14347,8 +16891,8 @@ snapshots: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 + get-intrinsic: 1.2.6 + gopd: 1.2.0 has-property-descriptors: 1.0.2 set-function-name@2.0.2: @@ -14365,6 +16909,33 @@ snapshots: inherits: 2.0.4 safe-buffer: 5.2.1 + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.0.3 + semver: 7.6.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.33.5 + '@img/sharp-darwin-x64': 0.33.5 + '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-linux-arm': 0.33.5 + '@img/sharp-linux-arm64': 0.33.5 + '@img/sharp-linux-s390x': 0.33.5 + '@img/sharp-linux-x64': 0.33.5 + '@img/sharp-linuxmusl-arm64': 0.33.5 + '@img/sharp-linuxmusl-x64': 0.33.5 + '@img/sharp-wasm32': 0.33.5 + '@img/sharp-win32-ia32': 0.33.5 + '@img/sharp-win32-x64': 0.33.5 + optional: true + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -14375,12 +16946,33 @@ snapshots: short-unique-id@5.2.0: {} - side-channel@1.0.6: + side-channel-list@1.0.0: dependencies: - call-bind: 1.0.7 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.2 + object-inspect: 1.13.3 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 + object-inspect: 1.13.3 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 + object-inspect: 1.13.3 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.3 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 siginfo@2.0.0: {} @@ -14388,6 +16980,12 @@ snapshots: signal-exit@4.1.0: {} + signale@1.4.0: + dependencies: + chalk: 2.4.2 + figures: 2.0.0 + pkg-conf: 2.1.0 + simple-concat@1.0.1: {} simple-get@4.0.1: @@ -14408,8 +17006,14 @@ snapshots: sisteransi@1.0.5: {} + skin-tone@2.0.0: + dependencies: + unicode-emoji-modifier-base: 1.0.0 + slash@3.0.0: {} + slash@5.1.0: {} + smart-buffer@4.2.0: {} snake-case@2.1.0: @@ -14460,7 +17064,7 @@ snapshots: socks-proxy-agent@8.0.4: dependencies: agent-base: 7.1.1 - debug: 4.3.7 + debug: 4.4.0 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -14472,7 +17076,7 @@ snapshots: sort-object-keys@1.1.3: {} - sort-package-json@2.12.0: + sort-package-json@2.14.0: dependencies: detect-indent: 7.0.1 detect-newline: 4.0.1 @@ -14494,8 +17098,28 @@ snapshots: space-separated-tokens@1.1.5: {} + spawn-error-forwarder@1.0.0: {} + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.20 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.20 + + spdx-license-ids@3.0.20: {} + split-ca@1.0.1: {} + split2@1.0.0: + dependencies: + through2: 2.0.5 + sprintf-js@1.0.3: {} sprintf-js@1.1.3: {} @@ -14525,6 +17149,11 @@ snapshots: std-env@3.8.0: {} + stream-combiner2@1.1.1: + dependencies: + duplexer2: 0.1.4 + readable-stream: 2.3.8 + streamsearch@1.1.0: {} streamx@2.20.1: @@ -14555,31 +17184,42 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.3 - string.prototype.matchall@4.0.11: + string.prototype.matchall@4.0.12: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.7 es-errors: 1.3.0 es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 - gopd: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.7 - regexp.prototype.flags: 1.5.2 + get-intrinsic: 1.2.6 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.3 set-function-name: 2.0.2 - side-channel: 1.0.6 + side-channel: 1.1.0 string.prototype.repeat@1.0.0: dependencies: define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.7 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.23.7 + es-object-atoms: 1.0.0 + has-property-descriptors: 1.0.2 string.prototype.trim@1.2.9: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.7 es-object-atoms: 1.0.0 string.prototype.trimend@1.0.8: @@ -14588,9 +17228,16 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 es-object-atoms: 1.0.0 @@ -14614,13 +17261,17 @@ snapshots: strip-final-newline@2.0.0: {} + strip-final-newline@3.0.0: {} + + strip-final-newline@4.0.0: {} + strip-json-comments@2.0.1: {} strip-json-comments@3.1.1: {} strnum@1.0.5: {} - styled-jsx@5.1.1(@babel/core@7.26.0)(react@19.0.0): + styled-jsx@5.1.6(@babel/core@7.26.0)(react@19.0.0): dependencies: client-only: 0.0.1 react: 19.0.0 @@ -14633,6 +17284,11 @@ snapshots: dependencies: postcss: 8.4.47 + super-regex@1.0.0: + dependencies: + function-timeout: 1.0.2 + time-span: 5.1.0 + superjson@2.2.2: dependencies: copy-anything: 3.0.5 @@ -14649,6 +17305,11 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-hyperlinks@3.1.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + supports-preserve-symlinks-flag@1.0.0: {} swagger-client@3.31.0: @@ -14674,7 +17335,7 @@ snapshots: transitivePeerDependencies: - debug - swagger-ui-react@5.18.2(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + swagger-ui-react@5.18.2(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@babel/runtime-corejs3': 7.25.6 '@braintree/sanitize-url': 7.0.4 @@ -14699,7 +17360,7 @@ snapshots: react-immutable-proptypes: 2.2.0(immutable@3.8.2) react-immutable-pure-component: 2.2.2(immutable@3.8.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react-inspector: 6.0.2(react@19.0.0) - react-redux: 9.1.2(@types/react@19.0.1)(react@19.0.0)(redux@5.0.1) + react-redux: 9.1.2(@types/react@19.0.7)(react@19.0.0)(redux@5.0.1) react-syntax-highlighter: 15.5.0(react@19.0.0) redux: 5.0.1 redux-immutable: 4.0.0(immutable@3.8.2) @@ -14726,7 +17387,7 @@ snapshots: synckit@0.9.2: dependencies: '@pkgr/core': 0.1.1 - tslib: 2.7.0 + tslib: 2.8.1 tabbable@6.2.0: {} @@ -14777,6 +17438,15 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 + temp-dir@3.0.0: {} + + tempy@3.1.0: + dependencies: + is-stream: 3.0.0 + temp-dir: 3.0.0 + type-fest: 2.19.0 + unique-string: 3.0.0 + terser-webpack-plugin@5.3.10(webpack@5.94.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -14802,7 +17472,7 @@ snapshots: testcontainers@10.16.0: dependencies: '@balena/dockerignore': 1.0.2 - '@types/dockerode': 3.3.32 + '@types/dockerode': 3.3.34 archiver: 7.0.1 async-lock: 1.4.1 byline: 5.0.0 @@ -14825,8 +17495,25 @@ snapshots: text-hex@1.0.0: {} + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + through2@2.0.5: + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + through@2.3.8: {} + time-span@5.1.0: + dependencies: + convert-hrtime: 5.0.0 + tiny-invariant@1.3.3: {} tinybench@2.9.0: {} @@ -14860,11 +17547,11 @@ snapshots: no-case: 2.3.2 upper-case: 1.1.3 - tldts-core@6.1.67: {} + tldts-core@6.1.69: {} - tldts@6.1.67: + tldts@6.1.69: dependencies: - tldts-core: 6.1.67 + tldts-core: 6.1.69 tmp@0.0.33: dependencies: @@ -14876,6 +17563,8 @@ snapshots: dependencies: is-number: 7.0.0 + toad-cache@3.7.0: {} + toggle-selection@1.0.6: {} toidentifier@1.0.1: {} @@ -14884,7 +17573,7 @@ snapshots: tough-cookie@5.0.0: dependencies: - tldts: 6.1.67 + tldts: 6.1.69 tr46@0.0.3: {} @@ -14892,6 +17581,8 @@ snapshots: dependencies: punycode: 2.3.1 + traverse@0.6.8: {} + tree-kill@1.2.2: {} tree-sitter-json@0.20.2: @@ -14912,47 +17603,46 @@ snapshots: triple-beam@1.4.1: {} - trpc-to-openapi@2.1.0(@trpc/server@11.0.0-rc.660(typescript@5.7.2))(zod-openapi@2.19.0(zod@3.24.1))(zod@3.24.1): + trpc-to-openapi@2.1.2(@trpc/server@11.0.0-rc.700(typescript@5.7.3))(zod-openapi@2.19.0(zod@3.24.1))(zod@3.24.1): dependencies: - '@trpc/server': 11.0.0-rc.660(typescript@5.7.2) + '@trpc/server': 11.0.0-rc.700(typescript@5.7.3) co-body: 6.2.0 h3: 1.13.0 - lodash.clonedeep: 4.5.0 - openapi3-ts: 4.3.3 + openapi3-ts: 4.4.0 zod: 3.24.1 zod-openapi: 2.19.0(zod@3.24.1) optionalDependencies: '@rollup/rollup-linux-x64-gnu': 4.6.1 - ts-api-utils@1.3.0(typescript@5.7.2): + ts-api-utils@2.0.0(typescript@5.7.3): dependencies: - typescript: 5.7.2 + typescript: 5.7.3 ts-mixer@6.0.4: {} - ts-node@10.9.2(@types/node@22.10.2)(typescript@5.7.2): + ts-node@10.9.2(@types/node@22.10.7)(typescript@5.7.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.10.2 + '@types/node': 22.10.7 acorn: 8.14.0 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.7.2 + typescript: 5.7.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 ts-toolbelt@9.6.0: {} - tsconfck@3.1.3(typescript@5.7.2): + tsconfck@3.1.3(typescript@5.7.3): optionalDependencies: - typescript: 5.7.2 + typescript: 5.7.3 tsconfig-paths@3.15.0: dependencies: @@ -14965,6 +17655,8 @@ snapshots: tslib@2.7.0: {} + tslib@2.8.1: {} + tsscmp@1.0.6: {} tsx@4.19.2: @@ -15015,7 +17707,11 @@ snapshots: type-fest@0.21.3: {} - type-fest@4.28.0: {} + type-fest@1.4.0: {} + + type-fest@2.19.0: {} + + type-fest@4.30.2: {} type-is@1.6.18: dependencies: @@ -15024,36 +17720,69 @@ snapshots: typed-array-buffer@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 is-typed-array: 1.1.13 + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + typed-array-byte-length@1.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 + gopd: 1.2.0 + has-proto: 1.2.0 is-typed-array: 1.1.13 + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + typed-array-byte-offset@1.0.2: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 + gopd: 1.2.0 + has-proto: 1.2.0 is-typed-array: 1.1.13 + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.9 + typed-array-length@1.0.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 + gopd: 1.2.0 + has-proto: 1.2.0 is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.0.0 + reflect.getprototypeof: 1.0.9 + typedarray-to-buffer@3.1.5: dependencies: is-typedarray: 1.0.0 @@ -15062,17 +17791,17 @@ snapshots: dependencies: ts-toolbelt: 9.6.0 - typescript-eslint@8.18.0(eslint@9.16.0)(typescript@5.7.2): + typescript-eslint@8.20.0(eslint@9.18.0)(typescript@5.7.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.18.0(@typescript-eslint/parser@8.18.0(eslint@9.16.0)(typescript@5.7.2))(eslint@9.16.0)(typescript@5.7.2) - '@typescript-eslint/parser': 8.18.0(eslint@9.16.0)(typescript@5.7.2) - '@typescript-eslint/utils': 8.18.0(eslint@9.16.0)(typescript@5.7.2) - eslint: 9.16.0 - typescript: 5.7.2 + '@typescript-eslint/eslint-plugin': 8.20.0(@typescript-eslint/parser@8.20.0(eslint@9.18.0)(typescript@5.7.3))(eslint@9.18.0)(typescript@5.7.3) + '@typescript-eslint/parser': 8.20.0(eslint@9.18.0)(typescript@5.7.3) + '@typescript-eslint/utils': 8.20.0(eslint@9.18.0)(typescript@5.7.3) + eslint: 9.18.0 + typescript: 5.7.3 transitivePeerDependencies: - supports-color - typescript@5.7.2: {} + typescript@5.7.3: {} uc.micro@2.1.0: {} @@ -15085,11 +17814,18 @@ snapshots: unbox-primitive@1.0.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 has-bigints: 1.0.2 - has-symbols: 1.0.3 + has-symbols: 1.1.0 which-boxed-primitive: 1.0.2 + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.3 + has-bigints: 1.0.2 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + uncrypto@0.1.3: {} undici-types@5.26.5: {} @@ -15100,7 +17836,7 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 - undici@7.1.0: {} + undici@7.2.3: {} unenv@1.10.0: dependencies: @@ -15110,10 +17846,24 @@ snapshots: node-fetch-native: 1.6.4 pathe: 1.1.2 + unicode-emoji-modifier-base@1.0.0: {} + + unicorn-magic@0.1.0: {} + + unicorn-magic@0.3.0: {} + unique-string@2.0.0: dependencies: crypto-random-string: 2.0.0 + unique-string@3.0.0: + dependencies: + crypto-random-string: 4.0.0 + + universal-github-app-jwt@2.2.0: {} + + universal-user-agent@7.0.2: {} + universalify@2.0.1: {} unpipe@1.0.0: {} @@ -15169,6 +17919,8 @@ snapshots: dependencies: punycode: 2.3.1 + url-join@5.0.0: {} + url-parse@1.5.10: dependencies: querystringify: 2.2.0 @@ -15176,19 +17928,12 @@ snapshots: url-toolkit@2.2.5: {} - use-callback-ref@1.3.2(@types/react@18.3.13)(react@19.0.0): + use-callback-ref@1.3.3(@types/react@19.0.7)(react@19.0.0): dependencies: react: 19.0.0 - tslib: 2.7.0 + tslib: 2.8.1 optionalDependencies: - '@types/react': 18.3.13 - - use-callback-ref@1.3.2(@types/react@19.0.1)(react@19.0.0): - dependencies: - react: 19.0.0 - tslib: 2.7.0 - optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.0.7 use-composed-ref@1.3.0(react@19.0.0): dependencies: @@ -15200,53 +17945,32 @@ snapshots: dequal: 2.0.3 react: 19.0.0 - use-intl@3.26.1(react@19.0.0): + use-intl@3.26.3(react@19.0.0): dependencies: '@formatjs/fast-memoize': 2.2.1 intl-messageformat: 10.7.1 react: 19.0.0 - use-isomorphic-layout-effect@1.1.2(@types/react@18.3.13)(react@19.0.0): + use-isomorphic-layout-effect@1.1.2(@types/react@19.0.7)(react@19.0.0): dependencies: react: 19.0.0 optionalDependencies: - '@types/react': 18.3.13 + '@types/react': 19.0.7 - use-isomorphic-layout-effect@1.1.2(@types/react@19.0.1)(react@19.0.0): + use-latest@1.2.1(@types/react@19.0.7)(react@19.0.0): dependencies: react: 19.0.0 + use-isomorphic-layout-effect: 1.1.2(@types/react@19.0.7)(react@19.0.0) optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.0.7 - use-latest@1.2.1(@types/react@18.3.13)(react@19.0.0): - dependencies: - react: 19.0.0 - use-isomorphic-layout-effect: 1.1.2(@types/react@18.3.13)(react@19.0.0) - optionalDependencies: - '@types/react': 18.3.13 - - use-latest@1.2.1(@types/react@19.0.1)(react@19.0.0): - dependencies: - react: 19.0.0 - use-isomorphic-layout-effect: 1.1.2(@types/react@19.0.1)(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.1 - - use-sidecar@1.1.2(@types/react@18.3.13)(react@19.0.0): + use-sidecar@1.1.2(@types/react@19.0.7)(react@19.0.0): dependencies: detect-node-es: 1.1.0 react: 19.0.0 - tslib: 2.7.0 + tslib: 2.8.1 optionalDependencies: - '@types/react': 18.3.13 - - use-sidecar@1.1.2(@types/react@19.0.1)(react@19.0.0): - dependencies: - detect-node-es: 1.1.0 - react: 19.0.0 - tslib: 2.7.0 - optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.0.7 use-sync-external-store@1.2.2(react@19.0.0): dependencies: @@ -15254,12 +17978,17 @@ snapshots: util-deprecate@1.0.2: {} - uuid@11.0.3: {} + uuid@11.0.4: {} uuid@8.3.2: {} v8-compile-cache-lib@3.0.1: {} + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + validate-npm-package-name@5.0.1: {} vary@1.1.2: {} @@ -15290,13 +18019,13 @@ snapshots: dependencies: global: 4.4.0 - vite-node@2.1.8(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): + vite-node@2.1.8(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): dependencies: cac: 6.7.14 - debug: 4.3.7 + debug: 4.4.0 es-module-lexer: 1.5.4 pathe: 1.1.2 - vite: 5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite: 5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) transitivePeerDependencies: - '@types/node' - less @@ -15308,33 +18037,33 @@ snapshots: - supports-color - terser - vite-tsconfig-paths@5.1.4(typescript@5.7.2)(vite@5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)): + vite-tsconfig-paths@5.1.4(typescript@5.7.3)(vite@5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)): dependencies: debug: 4.3.7 globrex: 0.1.2 - tsconfck: 3.1.3(typescript@5.7.2) + tsconfck: 3.1.3(typescript@5.7.3) optionalDependencies: - vite: 5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite: 5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) transitivePeerDependencies: - supports-color - typescript - vite@5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): + vite@5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): dependencies: esbuild: 0.21.5 postcss: 8.4.47 rollup: 4.21.3 optionalDependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 fsevents: 2.3.3 - sass: 1.83.0 + sass: 1.83.4 sugarss: 4.0.1(postcss@8.4.47) terser: 5.32.0 - vitest@2.1.8(@types/node@22.10.2)(@vitest/ui@2.1.8)(jsdom@25.0.1)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): + vitest@2.1.8(@types/node@22.10.7)(@vitest/ui@2.1.8)(jsdom@26.0.0)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0): dependencies: '@vitest/expect': 2.1.8 - '@vitest/mocker': 2.1.8(vite@5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) + '@vitest/mocker': 2.1.8(vite@5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0)) '@vitest/pretty-format': 2.1.8 '@vitest/runner': 2.1.8 '@vitest/snapshot': 2.1.8 @@ -15350,13 +18079,13 @@ snapshots: tinyexec: 0.3.1 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.5(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) - vite-node: 2.1.8(@types/node@22.10.2)(sass@1.83.0)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite: 5.4.5(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) + vite-node: 2.1.8(@types/node@22.10.7)(sass@1.83.4)(sugarss@4.0.1(postcss@8.4.47))(terser@5.32.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.10.2 + '@types/node': 22.10.7 '@vitest/ui': 2.1.8(vitest@2.1.8) - jsdom: 25.0.1 + jsdom: 26.0.0 transitivePeerDependencies: - less - lightningcss @@ -15434,7 +18163,7 @@ snapshots: whatwg-mimetype@4.0.0: {} - whatwg-url@14.0.0: + whatwg-url@14.1.0: dependencies: tr46: 5.0.0 webidl-conversions: 7.0.0 @@ -15449,23 +18178,32 @@ snapshots: is-bigint: 1.0.4 is-boolean-object: 1.1.2 is-number-object: 1.0.7 - is-string: 1.0.7 + is-string: 1.1.1 is-symbol: 1.0.4 - which-builtin-type@1.1.4: + which-boxed-primitive@1.1.1: dependencies: - function.prototype.name: 1.1.6 + is-bigint: 1.1.0 + is-boolean-object: 1.2.1 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.3 + function.prototype.name: 1.1.8 has-tostringtag: 1.0.2 is-async-function: 2.0.0 - is-date-object: 1.0.5 - is-finalizationregistry: 1.0.2 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 is-generator-function: 1.0.10 - is-regex: 1.1.4 - is-weakref: 1.0.2 + is-regex: 1.2.1 + is-weakref: 1.1.0 isarray: 2.0.5 - which-boxed-primitive: 1.0.2 + which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.15 + which-typed-array: 1.1.18 which-collection@1.0.2: dependencies: @@ -15477,9 +18215,18 @@ snapshots: which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 + call-bind: 1.0.8 for-each: 0.3.3 - gopd: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which-typed-array@1.1.18: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + for-each: 0.3.3 + gopd: 1.2.0 has-tostringtag: 1.0.2 which@2.0.2: @@ -15587,8 +18334,20 @@ snapshots: yaml@2.5.1: {} + yargs-parser@20.2.9: {} + yargs-parser@21.1.1: {} + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -15603,6 +18362,8 @@ snapshots: yocto-queue@0.1.0: {} + yoctocolors@2.1.1: {} + zenscroll@4.0.2: {} zip-stream@6.0.1: @@ -15611,7 +18372,7 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.5.2 - zod-form-data@2.0.2(zod@3.24.1): + zod-form-data@2.0.5(zod@3.24.1): dependencies: zod: 3.24.1 diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh new file mode 100644 index 000000000..54131a632 --- /dev/null +++ b/scripts/entrypoint.sh @@ -0,0 +1,25 @@ +#!/bin/sh +set -e + +export PUID=${PUID:-0} +export PGID=${PGID:-0} + +echo "Starting with UID='$PUID', GID='$PGID'" + +if [ "${PUID}" != "0" ] || [ "${PGID}" != "0" ]; then + # The below command will change the owner of all files in the /app directory (except node_modules) to the new UID and GID + echo "Changing owner to $PUID:$PGID, this will take about 10 seconds..." + find . -name 'node_modules' -prune -o -mindepth 1 -maxdepth 1 -exec chown -R $PUID:$PGID {} + + chown -R $PUID:$PGID /var/cache/nginx + chown -R $PUID:$PGID /var/log/nginx + chown -R $PUID:$PGID /var/lib/nginx + chown -R $PUID:$PGID /run/nginx/nginx.pid + chown -R $PUID:$PGID /etc/nginx + echo "Changing owner to $PUID:$PGID, done." +fi + +if [ "${PUID}" != "0" ]; then + su-exec $PUID:$PGID "$@" +else + exec "$@" +fi diff --git a/scripts/generateEncryptionKey.js b/scripts/generateEncryptionKey.js deleted file mode 100644 index 1fc7fdbfe..000000000 --- a/scripts/generateEncryptionKey.js +++ /dev/null @@ -1,7 +0,0 @@ -// This script generates a random encryption key -// This key is used to encrypt and decrypt the integration secrets -// In production it is generated in run.sh and stored in the environment variable ENCRYPTION_KEY -// during runtime, it's also stored in a file. - -const crypto = require("crypto"); -console.log(crypto.randomBytes(32).toString("hex")); diff --git a/scripts/run.sh b/scripts/run.sh index bc4d9c9b1..83833d5cd 100644 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -1,6 +1,7 @@ -# Creating folders in volume +# Create sub directories in volume mkdir -p /appdata/db mkdir -p /appdata/redis +mkdir -p /appdata/trusted-certificates # Run migrations if [ $DB_MIGRATIONS_DISABLED = "true" ]; then @@ -10,18 +11,8 @@ else node ./db/migrations/$DB_DIALECT/migrate.cjs ./db/migrations/$DB_DIALECT fi -# Generates an encryption key if it doesn't exist and saves it to /secrets/encryptionKey -# Also sets the ENCRYPTION_KEY environment variable -encryptionKey="" -if [ -r /secrets/encryptionKey ]; then - echo "Encryption key already exists" - encryptionKey=$(cat /secrets/encryptionKey) -else - echo "Generating encryption key" - encryptionKey=$(node ./generateEncryptionKey.js) - echo $encryptionKey > /secrets/encryptionKey -fi -export ENCRYPTION_KEY=$encryptionKey +# Auth secret is generated every time the container starts as it is required, but not used because we don't need JWTs or Mail hashing +export AUTH_SECRET=$(openssl rand -base64 32) # Start nginx proxy # 1. Replace the HOSTNAME in the nginx template file diff --git a/tooling/eslint/package.json b/tooling/eslint/package.json index c8a0dec2a..161ab38cf 100644 --- a/tooling/eslint/package.json +++ b/tooling/eslint/package.json @@ -17,19 +17,19 @@ }, "prettier": "@homarr/prettier-config", "dependencies": { - "@next/eslint-plugin-next": "^14.2.20", - "eslint-config-prettier": "^9.1.0", + "@next/eslint-plugin-next": "^15.1.4", + "eslint-config-prettier": "^10.0.1", "eslint-config-turbo": "^2.3.3", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsx-a11y": "^6.10.2", - "eslint-plugin-react": "^7.37.2", + "eslint-plugin-react": "^7.37.4", "eslint-plugin-react-hooks": "^5.1.0", - "typescript-eslint": "^8.18.0" + "typescript-eslint": "^8.20.0" }, "devDependencies": { "@homarr/prettier-config": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0", - "eslint": "^9.16.0", - "typescript": "^5.7.2" + "eslint": "^9.18.0", + "typescript": "^5.7.3" } } diff --git a/tooling/prettier/package.json b/tooling/prettier/package.json index 1f384f858..b843215da 100644 --- a/tooling/prettier/package.json +++ b/tooling/prettier/package.json @@ -10,12 +10,12 @@ }, "prettier": "@homarr/prettier-config", "dependencies": { - "@ianvs/prettier-plugin-sort-imports": "^4.4.0", + "@ianvs/prettier-plugin-sort-imports": "^4.4.1", "prettier": "^3.4.2" }, "devDependencies": { "@homarr/tsconfig": "workspace:^0.1.0", - "prettier-plugin-packagejson": "^2.5.6", - "typescript": "^5.7.2" + "prettier-plugin-packagejson": "^2.5.8", + "typescript": "^5.7.3" } } diff --git a/tooling/semver/package.json b/tooling/semver/package.json deleted file mode 100644 index 160e32039..000000000 --- a/tooling/semver/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@alparr/semver", - "private": true, - "version": "0.1.0", - "plugins": [ - "@semantic-release/commit-analyzer", - "@semantic-release/release-notes-generator", - "@semantic-release/changelog", - "@semantic-release/github", - "@semantic-release/npm", - "@semantic-release/git" - ] -} diff --git a/tooling/semver/release.config.cjs b/tooling/semver/release.config.cjs deleted file mode 100644 index 5b2b41cbd..000000000 --- a/tooling/semver/release.config.cjs +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @type {import('semantic-release').GlobalConfig} - */ -module.exports = { - branches: ["main"], - prepare: [ - "@semantic-release/changelog", - "@semantic-release/npm", - { - path: "@semantic-release/git", - assets: ["package.json", "package-lock.json", "CHANGELOG.md"], - message: - "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}", - }, - ], -}; diff --git a/turbo.json b/turbo.json index d4eea04f3..20ccadef0 100644 --- a/turbo.json +++ b/turbo.json @@ -1,8 +1,6 @@ { "$schema": "https://turborepo.org/schema.json", - "globalDependencies": [ - "**/.env" - ], + "globalDependencies": ["**/.env"], "globalEnv": [ "AUTH_LDAP_BASE", "AUTH_LDAP_BIND_DN", @@ -19,13 +17,13 @@ "AUTH_OIDC_ISSUER", "AUTH_OIDC_SCOPE_OVERWRITE", "AUTH_OIDC_GROUPS_ATTRIBUTE", + "AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE", "AUTH_LDAP_USERNAME_ATTRIBUTE", "AUTH_LDAP_USER_MAIL_ATTRIBUTE", "AUTH_LDAP_USERNAME_FILTER_EXTRA_ARG", "AUTH_OIDC_AUTO_LOGIN", "AUTH_LOGOUT_REDIRECT_URL", "AUTH_PROVIDERS", - "AUTH_SECRET", "AUTH_SESSION_EXPIRY_TIME", "CI", "DISABLE_REDIS_LOGS", @@ -40,53 +38,34 @@ "DOCKER_PORTS", "NODE_ENV", "PORT", - "SKIP_ENV_VALIDATION", - "VERCEL_URL" + "LOCAL_CERTIFICATE_PATH", + "SECRET_ENCRYPTION_KEY", + "SKIP_ENV_VALIDATION" ], "ui": "stream", "tasks": { "topo": { - "dependsOn": [ - "^topo" - ] + "dependsOn": ["^topo"] }, "build": { - "dependsOn": [ - "^build" - ], - "outputs": [ - ".next/**", - "!.next/cache/**", - "next-env.d.ts", - ".output/**", - ".vercel/output/**" - ] + "dependsOn": ["^build"], + "outputs": [".next/**", "!.next/cache/**", "next-env.d.ts", ".output/**", ".vercel/output/**"] }, "dev": { "persistent": true, "cache": false }, "format": { - "outputs": [ - "node_modules/.cache/.prettiercache" - ], + "outputs": ["node_modules/.cache/.prettiercache"], "outputLogs": "new-only" }, "lint": { - "dependsOn": [ - "^topo" - ], - "outputs": [ - "node_modules/.cache/.eslintcache" - ] + "dependsOn": ["^topo"], + "outputs": ["node_modules/.cache/.eslintcache"] }, "typecheck": { - "dependsOn": [ - "^topo" - ], - "outputs": [ - "node_modules/.cache/tsbuildinfo.json" - ] + "dependsOn": ["^topo"], + "outputs": ["node_modules/.cache/tsbuildinfo.json"] }, "clean": { "cache": false @@ -95,4 +74,4 @@ "cache": false } } -} \ No newline at end of file +} diff --git a/vercel.json b/vercel.json deleted file mode 100644 index 7ae9a3de5..000000000 --- a/vercel.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "github": { - "silent": true - } -}