From c92ca2af5fe4973c2eec1a78df24db875ba69269 Mon Sep 17 00:00:00 2001 From: ajnart Date: Thu, 13 Aug 2026 20:01:46 +0200 Subject: [PATCH] chore: reconcile performance layer after stack rebase --- .github/act/workshop.md | 19 - .github/workflows/deployment-docs.yml | 56 + .github/workflows/deployment-workshop.yml | 47 - AGENTS.md | 2 - apps/docs/.vscode/settings.json | 11 +- apps/docs/README.md | 26 +- .../advanced/command-line/_category_.json | 2 +- .../command-line/fix-usernames/index.mdx | 2 +- .../docs/docs/advanced/command-line/index.mdx | 10 +- .../command-line/integrations/index.mdx | 5 +- .../command-line/password-recovery/index.mdx | 4 +- .../advanced/command-line/users/index.mdx | 5 +- .../docs/advanced/development/_category_.json | 13 +- .../docs/advanced/development/kubernetes.mdx | 2 +- apps/docs/docs/advanced/proxy/index.mdx | 20 +- .../running-as-different-user/index.mdx | 20 +- .../docs/advanced/single-sign-on/index.mdx | 17 +- apps/docs/docs/advanced/styling/index.mdx | 30 +- apps/docs/docs/community/donate.mdx | 6 +- apps/docs/docs/community/get-in-touch.mdx | 4 +- apps/docs/docs/community/license.mdx | 3 +- apps/docs/docs/community/translations.mdx | 26 +- apps/docs/docs/getting-started/index.mdx | 13 +- .../getting-started/installation/docker.mdx | 42 +- .../docs/getting-started/installation/helm.md | 98 +- .../installation/home-assistant.mdx | 2 +- .../installation/portainer.mdx | 13 +- .../getting-started/installation/proxmox.mdx | 6 +- .../getting-started/installation/qnap.mdx | 2 +- .../getting-started/installation/runtipi.mdx | 17 +- .../getting-started/installation/saltbox.mdx | 3 +- .../getting-started/installation/source.mdx | 26 +- .../getting-started/installation/unraid.mdx | 13 +- .../docs/integrations/adguard-home/index.mdx | 49 +- apps/docs/docs/integrations/anchor/index.mdx | 51 +- apps/docs/docs/integrations/aria2/index.mdx | 51 +- .../integrations/audiobookshelf/index.mdx | 51 +- apps/docs/docs/integrations/bazarr/index.mdx | 52 +- apps/docs/docs/integrations/beszel/index.mdx | 60 +- apps/docs/docs/integrations/coolify/index.mdx | 67 +- .../docs/docs/integrations/dash-dot/index.mdx | 39 +- apps/docs/docs/integrations/deluge/index.mdx | 45 +- apps/docs/docs/integrations/docker/index.mdx | 46 +- apps/docs/docs/integrations/emby/index.mdx | 44 +- apps/docs/docs/integrations/glances/index.mdx | 50 +- apps/docs/docs/integrations/gluetun/index.mdx | 56 +- apps/docs/docs/integrations/gotify/index.mdx | 42 +- .../integrations/home-assistant/index.mdx | 52 +- apps/docs/docs/integrations/ical/index.mdx | 44 +- apps/docs/docs/integrations/immich/index.mdx | 37 +- .../docs/docs/integrations/jellyfin/index.mdx | 51 +- .../docs/integrations/jellyseerr/index.mdx | 65 +- .../docs/integrations/kubernetes/index.mdx | 18 +- apps/docs/docs/integrations/lidarr/index.mdx | 43 +- .../docs/integrations/navidrome/index.mdx | 22 +- .../docs/integrations/nextcloud/index.mdx | 55 +- apps/docs/docs/integrations/ntfy/index.mdx | 49 +- apps/docs/docs/integrations/nzbget/index.mdx | 45 +- .../integrations/open-media-vault/index.mdx | 62 +- .../docs/docs/integrations/opnsense/index.mdx | 84 +- .../docs/integrations/overseerr/index.mdx | 65 +- .../docs/integrations/paperless-ngx/index.mdx | 51 +- .../docs/docs/integrations/patchmon/index.mdx | 51 +- apps/docs/docs/integrations/peanut/index.mdx | 57 +- apps/docs/docs/integrations/pi-hole/index.mdx | 65 +- apps/docs/docs/integrations/plex/index.mdx | 58 +- .../docs/docs/integrations/prowlarr/index.mdx | 38 +- apps/docs/docs/integrations/proxmox/index.mdx | 136 +- .../docs/integrations/q-bittorent/index.mdx | 48 +- apps/docs/docs/integrations/radarr/index.mdx | 39 +- apps/docs/docs/integrations/readarr/index.mdx | 39 +- apps/docs/docs/integrations/sabnzbd/index.mdx | 41 +- apps/docs/docs/integrations/seerr/index.mdx | 65 +- apps/docs/docs/integrations/slskd/index.mdx | 43 +- apps/docs/docs/integrations/sonarr/index.mdx | 39 +- .../integrations/speedtest-tracker/index.mdx | 45 +- .../docs/docs/integrations/synology/index.mdx | 6 +- apps/docs/docs/integrations/tdarr/index.mdx | 46 +- .../integrations/technitium-dns/index.mdx | 88 +- .../docs/docs/integrations/tracearr/index.mdx | 47 +- .../docs/integrations/transmission/index.mdx | 41 +- apps/docs/docs/integrations/truenas/index.mdx | 88 +- apps/docs/docs/integrations/umami/index.mdx | 73 +- .../integrations/unifi-controller/index.mdx | 42 +- apps/docs/docs/integrations/unraid/index.mdx | 94 +- .../docs/integrations/uptime-kuma/index.mdx | 47 +- apps/docs/docs/management/backup.mdx | 8 +- .../docs/management/certificates/index.mdx | 24 +- .../docs/management/integrations/index.mdx | 25 +- apps/docs/docs/management/media/index.mdx | 3 +- .../docs/management/search-engines/index.mdx | 24 +- apps/docs/docs/management/tasks/index.mdx | 3 - apps/docs/docs/management/users/index.mdx | 41 +- .../widgets/immich-server-stats/index.mdx | 2 + apps/docs/package.json | 12 +- apps/docs/scripts/dump-contributors.mjs | 39 +- apps/docs/scripts/verify-algolia-search.mjs | 101 +- .../available-integrations.module.css | 26 +- .../pages/home/review-list/styles.module.css | 4 - apps/docs/src/pages/index.module.css | 1 - apps/docs/static/data/contributions.json | 128 +- .../data/translation-contributions.json | 967 +++++- .../boards/(content)/_board-add-menu.tsx | 84 - .../boards/(content)/_edit-actions.tsx | 4 +- .../boards/[name]/settings/_customCss.tsx | 52 +- .../settings/_layout-preview.module.css | 2 +- .../app/[locale]/boards/_layout-utils.spec.ts | 50 +- .../src/app/[locale]/boards/_layout-utils.ts | 78 +- .../src/app/[locale]/boards/_providers.tsx | 17 +- apps/nextjs/src/app/[locale]/layout.tsx | 52 +- .../_copy-ai-prompt-button.spec.ts | 55 - .../nextjs/src/app/[locale]/manage/layout.tsx | 42 +- .../assistant/assistant-widget-tool.tsx | 1 + .../advanced-focus/manual-surface.spec.ts | 2 +- .../board/items/actions/empty-position.ts | 2 +- .../board/items/lazy-item-move-modal.tsx | 67 - .../board/items/widget-query-recovery.ts | 2 +- .../board/items/widget-query-scope.spec.ts | 2 +- .../board/layout/test/board-lanes.spec.ts | 3 + .../board/sections/grid/grid-portal-host.tsx | 10 +- .../grid/test/grid-portal-host.spec.ts | 16 +- .../board-empty-space-context-menu.module.css | 4 - .../board-empty-space-context-menu.tsx | 226 -- .../sections/gridstack/gridstack.spec.ts | 11 - .../sections/gridstack/long-press.spec.ts | 17 - .../board/sections/gridstack/long-press.ts | 7 - .../board/sections/section-actions.spec.ts | 8 +- .../board/sections/section-actions.tsx | 2 +- .../board/sections/use-open-section-apps.ts | 26 +- .../components/onboarding/board-tour-gate.tsx | 2 +- .../src/components/user-avatar-menu.tsx | 12 +- .../install-from-workshop-buttons.tsx | 98 - .../workshop-install/workshop-api.ts | 47 - .../workshop-browser-modal.tsx | 221 -- .../pb_migrations/1750000000_init_workshop.js | 172 - .../1750000002_marketplace_view.js | 49 - apps/workshop/scripts/smoke-test.sh | 30 - e2e/board-advanced-interactions.spec.ts | 93 +- e2e/custom-widgets-custom-jsx-v2.spec.ts | 5 +- packages/api/src/mcp.ts | 2 - packages/api/src/router/test/board.spec.ts | 41 - .../api/src/router/test/custom-widget.spec.ts | 376 --- packages/api/src/router/widgets/downloads.ts | 63 +- .../src/router/widgets/health-monitoring.ts | 41 +- .../api/src/router/widgets/media-release.ts | 17 +- packages/api/src/router/widgets/rssFeed.ts | 2 +- .../api/src/router/widgets/uptime-kuma.ts | 39 +- packages/boards/src/layout-selection.ts | 5 +- .../mysql/0045_add_assistant_web_search.sql | 1 - .../migrations/mysql/meta/0038_snapshot.json | 504 +-- .../migrations/mysql/meta/0040_snapshot.json | 529 +--- .../migrations/mysql/meta/0041_snapshot.json | 527 +--- .../migrations/mysql/meta/0042_snapshot.json | 540 +--- .../migrations/mysql/meta/0047_snapshot.json | 2809 +++++++++++++++++ .../postgresql/0011_same_sir_ram.sql | 1 - .../postgresql/meta/0006_snapshot.json | 433 +-- .../postgresql/meta/0007_snapshot.json | 431 +-- .../postgresql/meta/0008_snapshot.json | 444 +-- .../postgresql/meta/0013_snapshot.json | 2670 ++++++++++++++++ .../sqlite/0042_add_layout_role.sql | 1 - .../sqlite/0043_swift_silver_samurai.sql | 1 - .../migrations/sqlite/meta/0038_snapshot.json | 453 +-- .../migrations/sqlite/meta/0039_snapshot.json | 451 +-- .../migrations/sqlite/meta/0040_snapshot.json | 464 +-- .../migrations/sqlite/meta/0045_snapshot.json | 2699 ++++++++++++++++ packages/db/schema/postgresql.ts | 2 +- packages/db/schema/sqlite.ts | 2 +- .../integrations/src/plex/plex-integration.ts | 4 +- packages/translation/src/lang/ca.json | 742 ++--- packages/translation/src/lang/cs.json | 742 ++--- packages/translation/src/lang/el.json | 742 ++--- packages/translation/src/lang/en.json | 80 +- packages/translation/src/lang/et.json | 742 ++--- packages/translation/src/lang/fi.json | 742 ++--- packages/translation/src/lang/fr.json | 691 ++-- packages/translation/src/lang/hr.json | 742 ++--- packages/translation/src/lang/hu.json | 742 ++--- packages/translation/src/lang/ko.json | 678 ++-- packages/translation/src/lang/lt.json | 742 ++--- packages/translation/src/lang/lv.json | 734 ++--- packages/translation/src/lang/pt-br.json | 692 ++-- packages/translation/src/lang/pt.json | 742 ++--- packages/translation/src/lang/sk.json | 742 ++--- packages/translation/src/lang/tr.json | 742 ++--- packages/translation/src/lang/uk.json | 736 ++--- packages/translation/src/lang/zh.json | 742 ++--- packages/widgets/src/app/component.tsx | 5 +- .../widgets/src/beszel-alerts/component.tsx | 95 +- packages/widgets/src/beszel-alerts/index.ts | 13 +- .../src/beszel-system-grid/component.tsx | 114 +- .../widgets/src/beszel-system-grid/index.ts | 1 - .../src/beszel-system-stats/component.tsx | 14 +- .../widgets/src/beszel-system-stats/index.ts | 1 - .../src/beszel-system-table/component.tsx | 116 +- .../widgets/src/beszel-system-table/index.ts | 1 - .../src/beszel/_shared/system-stats-modal.tsx | 1 - packages/widgets/src/bookmarks/component.tsx | 6 +- packages/widgets/src/calendar/component.tsx | 45 +- packages/widgets/src/catalog.ts | 2 + packages/widgets/src/clock/index.ts | 1 - packages/widgets/src/coolify/component.tsx | 129 +- .../widgets/src/coolify/instance-card.tsx | 58 +- .../widgets/src/coolify/servers-section.tsx | 54 +- .../widgets/src/coolify/services-section.tsx | 65 +- .../src/coolify/single-instance-layout.tsx | 56 +- .../src/dns-hole/controls/component.tsx | 26 +- packages/widgets/src/downloads/component.tsx | 78 +- packages/widgets/src/downloads/helpers.ts | 12 - packages/widgets/src/downloads/index.ts | 24 +- packages/widgets/src/errors/component.spec.ts | 1 - .../widgets/src/filter-storage-volumes.ts | 6 +- packages/widgets/src/firewall/component.tsx | 33 +- .../src/health-monitoring/system-health.tsx | 63 +- .../widgets/src/immich/albums-query.spec.ts | 11 +- packages/widgets/src/indexer-manager/index.ts | 1 - packages/widgets/src/manifest.spec.ts | 28 +- packages/widgets/src/manifest.ts | 2 + .../widgets/src/media-missing/component.tsx | 69 +- .../widgets/src/media-releases/component.tsx | 56 +- .../widgets/src/media-server/component.tsx | 28 +- .../src/media-transcoding/component.tsx | 16 +- packages/widgets/src/notebook/notebook.tsx | 19 +- .../widgets/src/notifications/component.tsx | 29 +- packages/widgets/src/notifications/index.ts | 2 +- packages/widgets/src/patchmon/index.ts | 48 +- packages/widgets/src/releases/index.ts | 2 +- packages/widgets/src/rssFeed/component.tsx | 87 +- packages/widgets/src/rssFeed/index.ts | 2 +- packages/widgets/src/stocks/index.ts | 2 +- .../widgets/src/system-disks/component.tsx | 146 +- .../src/system-resources/component.tsx | 94 +- packages/widgets/src/test/translation.spec.ts | 47 +- .../widgets/src/uptime-kuma/component.tsx | 81 +- packages/widgets/src/wud/component.tsx | 43 +- scripts/ci/workshop-act.sh | 22 - 235 files changed, 18492 insertions(+), 15756 deletions(-) delete mode 100644 .github/act/workshop.md create mode 100644 .github/workflows/deployment-docs.yml delete mode 100644 .github/workflows/deployment-workshop.yml delete mode 100644 apps/nextjs/src/app/[locale]/boards/(content)/_board-add-menu.tsx delete mode 100644 apps/nextjs/src/app/[locale]/manage/custom-widgets/_copy-ai-prompt-button.spec.ts delete mode 100644 apps/nextjs/src/components/board/items/lazy-item-move-modal.tsx delete mode 100644 apps/nextjs/src/components/board/sections/gridstack/board-empty-space-context-menu.module.css delete mode 100644 apps/nextjs/src/components/board/sections/gridstack/board-empty-space-context-menu.tsx delete mode 100644 apps/nextjs/src/components/board/sections/gridstack/gridstack.spec.ts delete mode 100644 apps/nextjs/src/components/board/sections/gridstack/long-press.spec.ts delete mode 100644 apps/nextjs/src/components/board/sections/gridstack/long-press.ts delete mode 100644 apps/nextjs/src/components/workshop-install/install-from-workshop-buttons.tsx delete mode 100644 apps/nextjs/src/components/workshop-install/workshop-api.ts delete mode 100644 apps/nextjs/src/components/workshop-install/workshop-browser-modal.tsx delete mode 100644 apps/workshop/pb_migrations/1750000000_init_workshop.js delete mode 100644 apps/workshop/pb_migrations/1750000002_marketplace_view.js delete mode 100755 apps/workshop/scripts/smoke-test.sh delete mode 100644 packages/api/src/router/test/custom-widget.spec.ts delete mode 100644 packages/db/migrations/mysql/0045_add_assistant_web_search.sql create mode 100644 packages/db/migrations/mysql/meta/0047_snapshot.json delete mode 100644 packages/db/migrations/postgresql/0011_same_sir_ram.sql create mode 100644 packages/db/migrations/postgresql/meta/0013_snapshot.json delete mode 100644 packages/db/migrations/sqlite/0042_add_layout_role.sql delete mode 100644 packages/db/migrations/sqlite/0043_swift_silver_samurai.sql create mode 100644 packages/db/migrations/sqlite/meta/0045_snapshot.json delete mode 100755 scripts/ci/workshop-act.sh diff --git a/.github/act/workshop.md b/.github/act/workshop.md deleted file mode 100644 index a0746d4aa..000000000 --- a/.github/act/workshop.md +++ /dev/null @@ -1,19 +0,0 @@ -# Workshop deployment with ACT - -The Workshop workflow builds the same image used on the VPS and smoke-tests both Docusaurus and PocketBase. Registry login and pushes are skipped under ACT. - -From the repository root: - -```sh -pnpm ci:act:workshop -``` - -The wrapper selects `.github/workflows/deployment-workshop.yml`, derives the active Docker socket (including Docker Desktop and OrbStack contexts), and runs only the `deploy` job using a `workflow_dispatch` event. - -To inspect the workflow without running it: - -```sh -act workflow_dispatch --list --workflows .github/workflows/deployment-workshop.yml -``` - -No GitHub or registry secrets are required for the local run. diff --git a/.github/workflows/deployment-docs.yml b/.github/workflows/deployment-docs.yml new file mode 100644 index 000000000..eeb53d101 --- /dev/null +++ b/.github/workflows/deployment-docs.yml @@ -0,0 +1,56 @@ +name: "[Deployment] Documentation" + +on: + push: + branches: ["dev"] + paths: + - "apps/docs/**" + - "packages/definitions/src/docs/**" + - ".github/workflows/deployment-docs.yml" + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +env: + SKIP_ENV_VALIDATION: true + TURBO_API: ${{ secrets.TURBO_API }} + TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v7 + - name: Setup + uses: ./tooling/github/setup + - name: Build docs + run: pnpm turbo build --filter=@homarr/docs + env: + CI: "true" + - name: Setup Pages + uses: actions/configure-pages@v6 + - name: Upload pages artifact + uses: actions/upload-pages-artifact@v5 + with: + path: "apps/docs/build" + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v5 diff --git a/.github/workflows/deployment-workshop.yml b/.github/workflows/deployment-workshop.yml deleted file mode 100644 index 621c4609c..000000000 --- a/.github/workflows/deployment-workshop.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: "[Deployment] Workshop" - -on: - push: - branches: ["dev"] - paths: - - "apps/docs/**" - - "apps/workshop/**" - workflow_dispatch: - -permissions: - contents: read - packages: write - -concurrency: - group: workshop-deployment - cancel-in-progress: true - -jobs: - deploy: - name: Build, test, and publish - runs-on: ubuntu-latest - timeout-minutes: 25 - env: - LOCAL_IMAGE: homarr/workshop:ci - REGISTRY_IMAGE: ghcr.io/homarr-labs/workshop - steps: - - name: Check out repository - uses: actions/checkout@v7 - - - name: Build combined Workshop image - run: docker build --file apps/workshop/Dockerfile --tag "$LOCAL_IMAGE" . - - - name: Smoke-test static docs and PocketBase - run: bash apps/workshop/scripts/smoke-test.sh "$LOCAL_IMAGE" - - - name: Log in to GitHub Container Registry - if: ${{ env.ACT != 'true' }} - run: echo "${{ github.token }}" | docker login ghcr.io --username "${{ github.actor }}" --password-stdin - - - name: Publish immutable and latest tags - if: ${{ env.ACT != 'true' }} - run: | - docker tag "$LOCAL_IMAGE" "$REGISTRY_IMAGE:sha-${GITHUB_SHA}" - docker tag "$LOCAL_IMAGE" "$REGISTRY_IMAGE:latest" - docker push "$REGISTRY_IMAGE:sha-${GITHUB_SHA}" - docker push "$REGISTRY_IMAGE:latest" diff --git a/AGENTS.md b/AGENTS.md index 716789f1b..6c3d36da4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -90,5 +90,3 @@ When modifying user-facing code, you MUST also update the corresponding document - Run `pnpm dev:cli -- build ` from a Homarr checkout to build `homarr:` with rebuild provenance. - Run `pnpm dev:cli -- build --pr ` to build a PR locally from a temporary checkout. - Run Go checks from `tools/homarr-dev` with `go test ./...` and `go vet ./...`. -- Use `dayjs` for date/time formatting or comparisons; do not hand-roll relative time or date math. -- Extract shared helpers/components when the same logic appears in multiple workshop/store files. diff --git a/apps/docs/.vscode/settings.json b/apps/docs/.vscode/settings.json index c5a1b2892..2eef88bf3 100644 --- a/apps/docs/.vscode/settings.json +++ b/apps/docs/.vscode/settings.json @@ -1,10 +1,3 @@ { - "cSpell.words": [ - "Homarr", - "Lidarr", - "Nextcloud", - "Radarr", - "Readarr", - "Sonarr" - ] -} \ No newline at end of file + "cSpell.words": ["Homarr", "Lidarr", "Nextcloud", "Radarr", "Readarr", "Sonarr"] +} diff --git a/apps/docs/README.md b/apps/docs/README.md index fbea63fa1..863ff66ec 100644 --- a/apps/docs/README.md +++ b/apps/docs/README.md @@ -21,8 +21,14 @@ pnpm dev:docs # Or from within this directory pnpm dev + +# Point the docs at a local PocketBase instance +WORKSHOP_API_URL=http://127.0.0.1:8090 pnpm dev:docs ``` +The standalone docs use `WORKSHOP_API_URL` for PocketBase and `HOMARR_WEBSITE_URL` for the public site origin. The old +`WORKSHOP_URL` name is a deprecated one-release alias. + ## Build ```bash @@ -40,7 +46,7 @@ Uses oxlint and oxfmt (same as the rest of the monorepo): ```bash pnpm lint # oxlint pnpm format # oxfmt (check) -pnpm format -- --write # oxfmt (fix) +pnpm format:fix # oxfmt (fix) ``` ## Typecheck @@ -71,7 +77,7 @@ Each integration/widget doc follows a consistent pattern: The docs app has `@homarr/definitions` as a workspace dependency. You can import integration kinds, widget kinds, and other definitions directly: ```typescript -import { IntegrationKind } from '@homarr/definitions'; +import { IntegrationKind } from "@homarr/definitions"; ``` This enables type-safe references to homarr domain concepts within documentation code. @@ -90,15 +96,15 @@ pnpm verify:search ## Tech Stack -| Layer | Technology | -|---|---| +| Layer | Technology | +| -------------- | ------------------------------------------- | | Site generator | Docusaurus 3 (`@docusaurus/preset-classic`) | -| Styling | Tailwind CSS 4 + Docusaurus Infima | -| Icons | `@tabler/icons-react` | -| Diagrams | Mermaid (`@docusaurus/theme-mermaid`) | -| Search | Algolia DocSearch | -| Analytics | PostHog | -| Charts | @nivo/line | +| Styling | Tailwind CSS 4 + Docusaurus Infima | +| Icons | `@tabler/icons-react` | +| Diagrams | Mermaid (`@docusaurus/theme-mermaid`) | +| Search | Algolia DocSearch | +| Analytics | PostHog | +| Charts | @nivo/line | ## Contributing diff --git a/apps/docs/docs/advanced/command-line/_category_.json b/apps/docs/docs/advanced/command-line/_category_.json index f3ee30aa5..4b4aec4c3 100644 --- a/apps/docs/docs/advanced/command-line/_category_.json +++ b/apps/docs/docs/advanced/command-line/_category_.json @@ -1,4 +1,4 @@ { "collapsed": true, "label": "Command line interface" -} \ No newline at end of file +} diff --git a/apps/docs/docs/advanced/command-line/fix-usernames/index.mdx b/apps/docs/docs/advanced/command-line/fix-usernames/index.mdx index d3b9f50cc..bf8808118 100644 --- a/apps/docs/docs/advanced/command-line/fix-usernames/index.mdx +++ b/apps/docs/docs/advanced/command-line/fix-usernames/index.mdx @@ -14,4 +14,4 @@ homarr fix-usernames This will convert all credential usernames to lowercase and update the database accordingly. -![](./img/screenshot-cli.png) \ No newline at end of file +![](./img/screenshot-cli.png) diff --git a/apps/docs/docs/advanced/command-line/index.mdx b/apps/docs/docs/advanced/command-line/index.mdx index 0e3e802f7..287985739 100644 --- a/apps/docs/docs/advanced/command-line/index.mdx +++ b/apps/docs/docs/advanced/command-line/index.mdx @@ -1,7 +1,7 @@ # Command line interface The Homarr image ships with a built-in recovery tool. This can be useful, if you do not have access to Homarr or if something is not working. -Please note that the CLI is an *emergency tool*, not an API tool. +Please note that the CLI is an _emergency tool_, not an API tool. :::caution @@ -12,10 +12,10 @@ You should also create a backup of the database, in case you break something. ## Execute CLI with Docker -1. Execute ``docker ps | grep homarr`` on the root system with Docker to find the container ID of your Homarr container. -2. Run ``docker exec -it /bin/bash homarr ``. \ -Replace ```` with your container ID from step 1. \ -Replace ```` with the command you want to execute (see sub-pages). +1. Execute `docker ps | grep homarr` on the root system with Docker to find the container ID of your Homarr container. +2. Run `docker exec -it /bin/bash homarr `. \ + Replace `` with your container ID from step 1. \ + Replace `` with the command you want to execute (see sub-pages). ## Execute CLI with QNAP diff --git a/apps/docs/docs/advanced/command-line/integrations/index.mdx b/apps/docs/docs/advanced/command-line/integrations/index.mdx index dfdb587b0..b958e9d2b 100644 --- a/apps/docs/docs/advanced/command-line/integrations/index.mdx +++ b/apps/docs/docs/advanced/command-line/integrations/index.mdx @@ -7,6 +7,7 @@ This guide requires that you understand [how to access the CLI](../). ::: Using these commands, you can manage the integrations from the CLI: + ```bash Group of commands to manage integrations @@ -43,7 +44,7 @@ Flags: ## Delete Integration - Requires a database connection -- Requires one parameter: ``id`` or ``name`` +- Requires one parameter: `id` or `name` - Deletes an integration permanently from the database ```bash @@ -57,4 +58,4 @@ Flags: -n, --name string Name of the integration -h, --help help for integrations delete -v, --version version for homarr-cli -``` \ No newline at end of file +``` diff --git a/apps/docs/docs/advanced/command-line/password-recovery/index.mdx b/apps/docs/docs/advanced/command-line/password-recovery/index.mdx index e5a80f669..844b44140 100644 --- a/apps/docs/docs/advanced/command-line/password-recovery/index.mdx +++ b/apps/docs/docs/advanced/command-line/password-recovery/index.mdx @@ -12,8 +12,8 @@ All sessions for that user will be terminated and the user must re-login. ![](./img/screenshot-cli.png) -Using the ``--username`` parameter, you can specify who you want to reset the password for. +Using the `--username` parameter, you can specify who you want to reset the password for. Executing the command will create a new random password, update the database and display the new password. All sessions for this user will be terminated and they must re-login. -![](./img/screenshot-cli-result.png) \ No newline at end of file +![](./img/screenshot-cli-result.png) diff --git a/apps/docs/docs/advanced/command-line/users/index.mdx b/apps/docs/docs/advanced/command-line/users/index.mdx index a867fa72d..93170259a 100644 --- a/apps/docs/docs/advanced/command-line/users/index.mdx +++ b/apps/docs/docs/advanced/command-line/users/index.mdx @@ -7,6 +7,7 @@ This guide requires that you understand [how to access the CLI](../). ::: Using these commands, you can manage the users from the CLI: + ```bash Group of commands to manage users @@ -42,7 +43,7 @@ yj52ek5cyb6du4bp4osbkjry admin xxxx@example.com ## Delete User - Requires a database connection -- Requires one parameter: ``id`` or ``username`` +- Requires one parameter: `id` or `username` ```bash Delete a user by id or username @@ -76,4 +77,4 @@ Flags: -p, --password New password -h, --help help for users update-password -v, --version version for homarr-cli -``` \ No newline at end of file +``` diff --git a/apps/docs/docs/advanced/development/_category_.json b/apps/docs/docs/advanced/development/_category_.json index 9f659a536..bf0464672 100644 --- a/apps/docs/docs/advanced/development/_category_.json +++ b/apps/docs/docs/advanced/development/_category_.json @@ -1,9 +1,8 @@ { - "label": "Developer guides", - "position": 6, - "collapsed": true, - "link": { - "type": "generated-index" - } + "label": "Developer guides", + "position": 6, + "collapsed": true, + "link": { + "type": "generated-index" } - \ No newline at end of file +} diff --git a/apps/docs/docs/advanced/development/kubernetes.mdx b/apps/docs/docs/advanced/development/kubernetes.mdx index e27b3ccbc..ff58b6c0a 100644 --- a/apps/docs/docs/advanced/development/kubernetes.mdx +++ b/apps/docs/docs/advanced/development/kubernetes.mdx @@ -132,4 +132,4 @@ This command should return CPU and memory usage statistics for each node. ## Conclusion -You have successfully set up a multi-node Kubernetes cluster using kind and installed the Metrics Server for monitoring resource usage. This setup is useful for local development and testing Kubernetes workloads before deploying them to a production environment. \ No newline at end of file +You have successfully set up a multi-node Kubernetes cluster using kind and installed the Metrics Server for monitoring resource usage. This setup is useful for local development and testing Kubernetes workloads before deploying them to a production environment. diff --git a/apps/docs/docs/advanced/proxy/index.mdx b/apps/docs/docs/advanced/proxy/index.mdx index 668031d9d..fbe33bfa4 100644 --- a/apps/docs/docs/advanced/proxy/index.mdx +++ b/apps/docs/docs/advanced/proxy/index.mdx @@ -9,16 +9,17 @@ tags: - Security --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; ## Allowing self-signed certificates + Some users may come across a barrier, where they're unable to receive a 200 response from the Ping widget for some apps, while using self-signed certificates or a local certificate authory. :::note What's going on? Homarr is trying to communicate to your apps via the integrations. -It usually doesn't matter if Homarr is running on ``http`` or ``https``. +It usually doesn't matter if Homarr is running on `http` or `https`. Your apps have a self-signed certificate - Homarr will recognize that the certificate was signed by an unknown authority and requests will be blocked. ::: @@ -28,8 +29,9 @@ To allow self-signed certificates, you can configure them on the certificates ma ## Securing Homarr with Traefik Copying the configuration straight from the docker-compose file won't work if you are running Homarr behind Traefik, such as a Portainer setup, or docker-swarm. In that case, you should use the following slightly modified configuration: + ```yaml -version: '3' +version: "3" services: homarr: container_name: homarr @@ -53,11 +55,12 @@ networks: external: true ``` -
+
A sample Traefik docker-compose.yml using Cloudflare for certificate generation that works with the configuration above would be: + ```yaml -version: '3' +version: "3" apps: traefik: @@ -103,7 +106,6 @@ networks: external: true ``` - :::tip Of particular note here is that both configurations explicitly define which network they are using, in this case "proxy", but it can be named anything. It just has to be the same across all apps for which Traefik is serving as a proxy. These are marked as external because the proxy network was manually created by running: `docker network create proxy` but this might be unnecessary depending on HOW exactly you are running Traefik. For example, if running [Traefik with Portainer](https://docs.portainer.io/advanced/reverse-proxy/traefik#deploying-in-a-docker-standalone-scenario), you can follow their official docs on how to set up Traefik and Portainer together, and you can just focus on the Homarr docker labels instead. ::: @@ -114,7 +116,6 @@ If you are using Caddy as the reverse proxy for your setup, your `docker-compose ```yaml services: - # <-- [Homarr installation] caddy: @@ -140,14 +141,17 @@ networks: proxy: external: true ``` + :::important Homarr needs to be on the same network so you will need to add the following property to your homarr install: + ```yaml homarr: ... networks: - proxy ``` + ::: Next, create a file named `Caddyfile` at the same level as your `docker-compose.yml` file with the following content: diff --git a/apps/docs/docs/advanced/running-as-different-user/index.mdx b/apps/docs/docs/advanced/running-as-different-user/index.mdx index a4ebcf0f4..91c02fb9d 100644 --- a/apps/docs/docs/advanced/running-as-different-user/index.mdx +++ b/apps/docs/docs/advanced/running-as-different-user/index.mdx @@ -8,7 +8,7 @@ tags: - PUID --- -By default the container is running with user `root` and group `root`. +By default the container is running with user `root` and group `root`. You can change the user and group by using the `PUID` and `PGID` environment variables. Important to note is, that you'll also need to change the permissions for the mounted directories accordingly. @@ -32,11 +32,11 @@ services: volumes: - ./homarr/appdata:/appdata environment: - - SECRET_ENCRYPTION_KEY=your_64_character_hex_string # <--- can be generated with `openssl rand -hex 32` - - PUID=1000 - - PGID=1000 + - SECRET_ENCRYPTION_KEY=your_64_character_hex_string # <--- can be generated with `openssl rand -hex 32` + - PUID=1000 + - PGID=1000 ports: - - '7575:7575' + - "7575:7575" ``` After that you'll need to create the appdata directory and set the correct permissions: @@ -76,11 +76,11 @@ services: - /var/run/docker.sock:/var/run/docker.sock - ./homarr/appdata:/appdata environment: - - SECRET_ENCRYPTION_KEY=your_64_character_hex_string # <--- can be generated with `openssl rand -hex 32` - - PUID=1000 - - PGID=999 + - SECRET_ENCRYPTION_KEY=your_64_character_hex_string # <--- can be generated with `openssl rand -hex 32` + - PUID=1000 + - PGID=999 ports: - - '7575:7575' + - "7575:7575" ``` And set the permissions for the mounted directories: @@ -90,4 +90,4 @@ mkdir -p ./homarr/appdata chown -R 1000:999 ./homarr/appdata ``` -Important here is that the group ID is set to `999` as we created the `docker` group with this ID. \ No newline at end of file +Important here is that the group ID is set to `999` as we created the `docker` group with this ID. diff --git a/apps/docs/docs/advanced/single-sign-on/index.mdx b/apps/docs/docs/advanced/single-sign-on/index.mdx index ae1d9ca31..505fe9867 100644 --- a/apps/docs/docs/advanced/single-sign-on/index.mdx +++ b/apps/docs/docs/advanced/single-sign-on/index.mdx @@ -10,20 +10,21 @@ tags: - Active Directory --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; # Single Sign On Homarr supports multiple authentication options, from internal userbase (credentials), to LDAP (with Active directory support), and OIDC. ### Auth configuration common variables -| Environment Variable | Description | Default Value | -|---------------------------|-------------|---------------| -| AUTH_PROVIDERS | Select Which provider to use between *credentials*, *ldap* and *oidc*.
Multiple providers can be enabled with by separating them with `,`, (ex. `AUTH_PROVIDERS=credentials,oidc`, it is highly recommended to just enable one provider). | credentials | -| AUTH_LOGOUT_REDIRECT_URL | URL to redirect to after clicking logging out. | --- | -| AUTH_SESSION_EXPIRY_TIME | Time for the session to time out. Can be set as pure number, which will automatically be used in seconds, or followed by s, m, h or d for seconds, minutes, hours or days. (ex: "30m") | "30d" | -| AUTH_COOKIE_PREFIX | Prefix used for all authentication cookies (session, csrf, callback, pkce, state, nonce). Change this if you run another Auth.js/NextAuth app on the same hostname as Homarr (browsers scope cookies by host, not by port) to avoid cookie name collisions. Only letters, numbers, hyphens and underscores are allowed. | `homarr` | + +| Environment Variable | Description | Default Value | +| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| AUTH_PROVIDERS | Select Which provider to use between _credentials_, _ldap_ and _oidc_.
Multiple providers can be enabled with by separating them with `,`, (ex. `AUTH_PROVIDERS=credentials,oidc`, it is highly recommended to just enable one provider). | credentials | +| AUTH_LOGOUT_REDIRECT_URL | URL to redirect to after clicking logging out. | --- | +| AUTH_SESSION_EXPIRY_TIME | Time for the session to time out. Can be set as pure number, which will automatically be used in seconds, or followed by s, m, h or d for seconds, minutes, hours or days. (ex: "30m") | "30d" | +| AUTH_COOKIE_PREFIX | Prefix used for all authentication cookies (session, csrf, callback, pkce, state, nonce). Change this if you run another Auth.js/NextAuth app on the same hostname as Homarr (browsers scope cookies by host, not by port) to avoid cookie name collisions. Only letters, numbers, hyphens and underscores are allowed. | `homarr` | diff --git a/apps/docs/docs/advanced/styling/index.mdx b/apps/docs/docs/advanced/styling/index.mdx index 9be382ec3..56d4305e5 100644 --- a/apps/docs/docs/advanced/styling/index.mdx +++ b/apps/docs/docs/advanced/styling/index.mdx @@ -19,12 +19,14 @@ Homarr uses https://mantine.dev/ under the hood. You can change the look & feel using custom CSS, that extends or overwrites the styles from Mantine. ## Getting into CSS + If you don't have any experience with CSS, we strongly recommend you to go through the courses here: https://www.w3schools.com/css/. Due to the infinite scenarios and setups possible with custom CSS, our support team will not provide any support with your own written CSS. ## Limitations and dangers + When using custom CSS, you can break the page or certain functionalities. Although CSS can improve the design & feel of the page, it **cannot do any of the following**: @@ -33,21 +35,23 @@ Although CSS can improve the design & feel of the page, it **cannot do any - Completely revamp the design of the page, only smaller changes are possible Here are some dangers of using custom CSS: + - Updates may contain breaking changes in the structure, built-in styling or how styling is processed. Therefore, -custom CSS may break unexpectedly without any warning + custom CSS may break unexpectedly without any warning - Custom CSS may make certain elements invisible or not possible to click / interact with - Custom CSS could make readability and accessibility worse for impaired people ## How to inspect the page -When styling the page, you can use the ``Inspector`` to inspect elements on the page and try out styles. + +When styling the page, you can use the `Inspector` to inspect elements on the page and try out styles. This may vary depending on your browser and operating system, but the workflow usually goes like this: - Open the Homarr page -- Press ``Ctrl`` + ``Shift`` + ``I`` at the same time. -Alternatively, right-click on the page and choose ``Inspect`` or ``Inspect element``. -- Open the tab ``Elements`` if it isn't open yet. +- Press `Ctrl` + `Shift` + `I` at the same time. + Alternatively, right-click on the page and choose `Inspect` or `Inspect element`. +- Open the tab `Elements` if it isn't open yet. - Search the element you want to change in the DOM tree or use the element picker (usually at the top left) -to select it by clicking on the page. + to select it by clicking on the page. - Experiment by changing the CSS code on the right side When writing custom CSS, it is important to also remember or create a selector, which tells the browser @@ -55,17 +59,19 @@ which element to apply the styles to. If you accidentally broke something or wan simply reload the page. ## Using Homarr's classes + Homarr's elements will already have a lot of classes and styles pre-applied. You can reuse those classes to apply additional styles or overwrite them. -When overwriting, remember to add the ``!important`` flag to your CSS property to tell the browser to use our instruction instead. +When overwriting, remember to add the `!important` flag to your CSS property to tell the browser to use our instruction instead. -Classes with random number suffixes, such as ``mantine-Card-x2fske``, should be avoided, since those are dynamic +Classes with random number suffixes, such as `mantine-Card-x2fske`, should be avoided, since those are dynamic CSS classes that will change with every build. This means, every time you update Homarr, your styles will no longer apply to them ## Defining custom classes for widgets + If you want to apply the styles only for one widget, you can define custom class names only for that widget. -To do that, enter edit mode on your board, click the three dots of your widget, click ``Edit item`` and click ``Advanced options``. +To do that, enter edit mode on your board, click the three dots of your widget, click `Edit item` and click `Advanced options`. Then, you can enter as many custom classes as you'd like: ![](./img/widget-custom-classes.png) @@ -73,6 +79,7 @@ Then, you can enter as many custom classes as you'd like: To save them, click `Save changes` on both modals and exit edit mode. ## Where to enter custom CSS + After you wrote your custom CSS, it is time to permanently save it, so you don't need to use the inspector anymore. To do this, enter the board settings: @@ -84,11 +91,12 @@ Here you can enter your CSS code, which will be applied on the respective board ![](./img/custom-css-setting.png) ## Using variables + You can also change the values of the theme variables, which are located here: https://mantine.dev/styles/css-variables-list/. To do this, see the following example CSS: ```css :root { - --mantine-primary-color-filled: #ffbb00; + --mantine-primary-color-filled: #ffbb00; } -``` \ No newline at end of file +``` diff --git a/apps/docs/docs/community/donate.mdx b/apps/docs/docs/community/donate.mdx index aeb95dcac..3651a2a7b 100644 --- a/apps/docs/docs/community/donate.mdx +++ b/apps/docs/docs/community/donate.mdx @@ -7,12 +7,15 @@ tags: --- # Donate + ## Why to donate + Our team of 4 developers is working on Homarr in their free time. Homarr has become a big part of our daily things we work on - and therefore we invest a lot of time into maintaining Homarr, providing support and implementing new features. We also incur monetary costs while developing Homarr for the tools that we need. A few examples include: + - Renting for a Cloud VPS for our cloud services (status page, monitoring, email, analytics, [demo instance](https://demo.homarr.dev/), ...) - Paying for (IDE-) licenses @@ -20,6 +23,7 @@ Using a donation, you help us to cover these expenses and enable the development Homarr is completely free to use. We'd highly appreciate if you consider donating, especially if you use Homarr in a commercial environment. ## Where to donate + We accept donations on our official [OpenCollective](https://opencollective.com/homarr). You may also sponsor us directly by providing a useful service / product to us other means. -You can get into contact with us [here](/docs/community/get-in-touch). \ No newline at end of file +You can get into contact with us [here](/docs/community/get-in-touch). diff --git a/apps/docs/docs/community/get-in-touch.mdx b/apps/docs/docs/community/get-in-touch.mdx index 7651f5ea2..eecd2e1f3 100644 --- a/apps/docs/docs/community/get-in-touch.mdx +++ b/apps/docs/docs/community/get-in-touch.mdx @@ -9,16 +9,16 @@ tags: We're happy to talk with you! Shoot us a message at the following places: ## E-Mail + We are open to discuss sponsorships, security vulnerabilities and other private requests through our email. Please do not report any bugs / feature requests here - they will be ignored and deleted. [homarr-labs@proton.me](mailto:homarr-labs@proton.me) ## Discord + We have a Discord Server, where we announce new releases, discuss features and bugs and show off our dashboards. There are over 4'000 members and we're happy to answer your questions or concerns. You're also open to discuss new / upcoming features and any offtopic selfhosting content. [_![](https://discordapp.com/api/guilds/972958686051962910/widget.png?style=banner2)_](https://discord.gg/aCsmEV5RgA) - - diff --git a/apps/docs/docs/community/license.mdx b/apps/docs/docs/community/license.mdx index e36a5d684..3d1f82890 100644 --- a/apps/docs/docs/community/license.mdx +++ b/apps/docs/docs/community/license.mdx @@ -7,6 +7,7 @@ tags: Homarr is licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0). ## TL;DR + | Action | Allowed | | -------------- | ------- | | Copy | ✅ | @@ -24,8 +25,6 @@ Please consider [making a donation](/docs/community/donate) to Homarr, if this p ::: - - ## Full License ```txt diff --git a/apps/docs/docs/community/translations.mdx b/apps/docs/docs/community/translations.mdx index 074db939d..68eea8a1e 100644 --- a/apps/docs/docs/community/translations.mdx +++ b/apps/docs/docs/community/translations.mdx @@ -5,30 +5,31 @@ tags: - Translations --- -We want to make Homarr accessible for everyone. -But to do that, we need your help. -We are running a community program that enables everyone to translate Homarr into their language – no programming required. -We are using [Crowdin](https://crowdin.com/) to manage our translations. +We want to make Homarr accessible for everyone. +But to do that, we need your help. +We are running a community program that enables everyone to translate Homarr into their language – no programming required. +We are using [Crowdin](https://crowdin.com/) to manage our translations. You can find the translations [here](https://translate.homarr.dev/). ## How to translate - ### Using crowdin's online platform -Go to the [Crowdin translations](https://translate.homarr.dev/) and select a language you want to translate. -You can then enter the translation mode and start translating. -After you've submitted your translations, a Proofreader will review your changes. -After a translation has been approved, it will be merged to the language development branch. -We merge this one periodically to the development branch. + +Go to the [Crowdin translations](https://translate.homarr.dev/) and select a language you want to translate. +You can then enter the translation mode and start translating. +After you've submitted your translations, a Proofreader will review your changes. +After a translation has been approved, it will be merged to the language development branch. +We merge this one periodically to the development branch. After the next update of Homarr, all changes from the development branch will be merged, including the changes in the translations. ### Using live translate + You can also help translate homarr directly from the app! For this you can simply change your language to "Crowdin (live translations)" ![](./img/crowdin-language-select.png) -Then you'll be prompted to connect to your Crowdin account and choose the language in which you want to transalte. +Then you'll be prompted to connect to your Crowdin account and choose the language in which you want to transalte. You can then start translating directly from the app by selecting some text on the app. If some text cannot be selected to be edited with the live translation tool, you can still translate it inside of the In-Context popup at the Home tab, it will be red if it's not translated yet. @@ -47,7 +48,8 @@ Do you want to become a proofreader? [Let us know on our Discord](/docs/communit ::: ## Guidelines + 1. Translate with context: Some translations can't be translated 1:1 - they need context. Ensure that your translations make sense in the context. 2. Keep things simple and original - no additional characters are needed. 3. Don't translate the same thing twice - if you see a translation that is already translated, don't translate it again unless you have a better translation. -5. Keep your translations as close to the original as possible. +4. Keep your translations as close to the original as possible. diff --git a/apps/docs/docs/getting-started/index.mdx b/apps/docs/docs/getting-started/index.mdx index 4dc986658..0d6a44a4e 100644 --- a/apps/docs/docs/getting-started/index.mdx +++ b/apps/docs/docs/getting-started/index.mdx @@ -8,13 +8,14 @@ tags: - Unraid --- -import Link from '@docusaurus/Link'; -import { IconArrowRight } from '@tabler/icons-react'; +import Link from "@docusaurus/Link"; +import { IconArrowRight } from "@tabler/icons-react"; Before you try to install Homarr, please review if your device meets the requirements. Installing on an unsupported device may lead to unstable behaviour and no support will be provided. ## Hardware + - At least 500MB RAM - At least 600MB of free disk space for the Docker image. SSD is preferred. - Single or dual core CPU @@ -24,8 +25,8 @@ Installing on an unsupported device may lead to unstable behaviour and no suppor We build Homarr for a bunch of different architectures, including ARM. Please ensure that your device architecture is supported by Homarr. We won't be able to provide support for unusual or outdated architectures. -| Architecture | Supported | -|--------------|-----------------| +| Architecture | Supported | +| ------------ | ---------------- | | linux/amd64 | ✅ Supported | | linux/arm64 | ✅ Supported | | linux/arm/v7 | ❌ Not supported | @@ -34,10 +35,10 @@ We build Homarr for a bunch of different architectures, including ARM. Please en -
+
Go to Installation
diff --git a/apps/docs/docs/getting-started/installation/docker.mdx b/apps/docs/docs/getting-started/installation/docker.mdx index 956a6c2d6..5a56a848a 100644 --- a/apps/docs/docs/getting-started/installation/docker.mdx +++ b/apps/docs/docs/getting-started/installation/docker.mdx @@ -1,21 +1,23 @@ -import { DockerInstallSnippet } from '@site/src/components/pages/installation/docker/dynamic-docker-install' +import { DockerInstallSnippet } from "@site/src/components/pages/installation/docker/dynamic-docker-install"; # Docker + Docker is our recommended installation method for beginners and professionals. It is easy to use, ships with all dependencies inside a single container and is easy to use and maintain. It requires at least some basic knowledge of [Docker](https://www.docker.com/). We recommend [NetworkChuck's Docker Containers 101](https://www.youtube.com/watch?v=eGz9DS-aIeY) as a good start for complete beginners. ## Docker compose + ### Prerequisites - A Linux or Windows based system that meets the [hardware prerequisites](/docs/getting-started/#hardware) and [architecture prerequisites](/docs/getting-started/#architecture). - [Docker](https://docs.docker.com/get-docker/) -- [Docker Compose](https://docs.docker.com/compose/install/) - *preinstalled on many systems nowadays* +- [Docker Compose](https://docs.docker.com/compose/install/) - _preinstalled on many systems nowadays_ ### Installation - + Finally, run ``docker compose up -d`` in the same directory. This will start the Homarr container in the background. :::caution @@ -26,27 +28,26 @@ Docker compose creates a network by default. Some integrations may not work (spe ### Updating -To update, navigate to the directory with the ``docker-compose.yaml`` located. +To update, navigate to the directory with the `docker-compose.yaml` located. -- Stop Homarr using ``docker compose down`` -- Pull the newest image of Homarr using ``docker compose pull`` -- Start Homarr again using ``docker compose up -d`` (``-d`` for detached mode - start in background) -- Delete the old image using ``docker image prune`` (*Warning: this also removes you other unused images - not just Homarr*) +- Stop Homarr using `docker compose down` +- Pull the newest image of Homarr using `docker compose pull` +- Start Homarr again using `docker compose up -d` (`-d` for detached mode - start in background) +- Delete the old image using `docker image prune` (_Warning: this also removes you other unused images - not just Homarr_) You can automate this process using [Watchtower](https://containrrr.dev/watchtower/). ### Uninstalling -To uninstall, navigate to the directory with the ``docker-compose.yaml`` located. +To uninstall, navigate to the directory with the `docker-compose.yaml` located. -- Stop Homarr using ``docker compose down`` -- Delete the created directories & files on your root file system (check ``docker-compose.yaml`` file for your specific locations) -- Delete compose file using ``rm docker-compose.yaml`` -- Prune unused Docker images using ``docker image prune`` (*Warning: this also removes you other unused images - not just Homarr*) +- Stop Homarr using `docker compose down` +- Delete the created directories & files on your root file system (check `docker-compose.yaml` file for your specific locations) +- Delete compose file using `rm docker-compose.yaml` +- Prune unused Docker images using `docker image prune` (_Warning: this also removes you other unused images - not just Homarr_) - (Optional): Prune any network or volumes if you use any. - (Optional): Remove Homarr from your reverse proxy, VPNs or tunnels if you use any. - ## Docker standalone :::caution @@ -77,15 +78,16 @@ docker run \ :::note -Docker will mount the configuration files and icons to your host machine. Please make sure to replace ```` from the docker run command with your desired storage location. The path must be absolute. +Docker will mount the configuration files and icons to your host machine. Please make sure to replace `` from the docker run command with your desired storage location. The path must be absolute. ::: ### Updating + To update Homarr, you must remove your container first. Make sure that you've mounted your data and that you have access to it, so your configuration doesn't get lost. -1. Run ``docker rm homarr`` to remove the container. -2. Pull the latest Homarr image ``docker pull ghcr.io/homarr-labs/homarr:latest``. +1. Run `docker rm homarr` to remove the container. +2. Pull the latest Homarr image `docker pull ghcr.io/homarr-labs/homarr:latest`. 3. Re-run the command you used to install Homarr. This process can get tideous, if you update frequently. Thus, we recommend [using docker-compose](#docker-compose) @@ -98,8 +100,8 @@ Want to update all your containers automatically? Checkout [Watchtower](https:// ### Uninstalling -1. Obtain the container ID of your Homarr container using ``docker ps | grep homarr``. -2. Delete the container using ``docker rm `` -3. Prune unused Docker images using ``docker image prune`` (*Warning: this also removes you other unused images - not just Homarr*) +1. Obtain the container ID of your Homarr container using `docker ps | grep homarr`. +2. Delete the container using `docker rm ` +3. Prune unused Docker images using `docker image prune` (_Warning: this also removes you other unused images - not just Homarr_) 4. (Optional): Prune any network or volumes if you use any. 5. (Optional): Remove Homarr from your reverse proxy, VPNs or tunnels if you use any. diff --git a/apps/docs/docs/getting-started/installation/helm.md b/apps/docs/docs/getting-started/installation/helm.md index c695d70b6..7507cdc18 100644 --- a/apps/docs/docs/getting-started/installation/helm.md +++ b/apps/docs/docs/getting-started/installation/helm.md @@ -12,7 +12,7 @@ A Helm chart to deploy homarr for Kubernetes ## Source Code -* +- ## Requirements @@ -76,38 +76,38 @@ To avoid including sensitive information in plain text within your version contr Below is an exhaustive list of all secrets: -| FEATURE | SECRET NAME | SECRET KEYS | Required | -|-----------|-------------------------|-----------------------------------------|----------| -| OIDC | auth-oidc-secret | oidc-client-id
oidc-client-secret | No | -| LDAP | auth-ldap-secret | bind-password | No | -| DATABASE | db-secret | db-url | No | -| DATABASE | db-encryption | db-encryption-key | yes | +| FEATURE | SECRET NAME | SECRET KEYS | Required | +| -------- | ---------------- | ------------------------------------ | -------- | +| OIDC | auth-oidc-secret | oidc-client-id
oidc-client-secret | No | +| LDAP | auth-ldap-secret | bind-password | No | +| DATABASE | db-secret | db-url | No | +| DATABASE | db-encryption | db-encryption-key | yes | ### Database You have multiple options for configuring the database: -| DRIVER TYPE | Persistence mode | -|----------------|---------------------------------| -| better-sqlite3 | Pod disk | -| better-sqlite3 | homarr-database PVC | -| mysql2 | External MySql database | -| node-postgres | External Postgresql database | +| DRIVER TYPE | Persistence mode | +| -------------- | ---------------------------- | +| better-sqlite3 | Pod disk | +| better-sqlite3 | homarr-database PVC | +| mysql2 | External MySql database | +| node-postgres | External Postgresql database | #### Pod disk -No additional configuration is required. However, keep in mind that if the pod restarts, all data will be lost. This setup is not *recommended* for production use. +No additional configuration is required. However, keep in mind that if the pod restarts, all data will be lost. This setup is not _recommended_ for production use. To create the necessary database secret, execute the following command:
Required Secrets -````yaml +```yaml kubectl create secret generic db-encryption \ --from-literal=db-encryption-key='' \ --namespace homarr -```` +```
@@ -120,11 +120,11 @@ Associated secret to create :
DB Required Secrets -````yaml +```yaml kubectl create secret generic db-encryption \ --from-literal=db-encryption-key='' \ --namespace homarr -```` +```
@@ -133,13 +133,13 @@ Bellow an example of the override value file :
values.yaml -````yaml +```yaml persistence: homarrDatabase: enabled: true storageClassName: "default" size: "1Gi" -```` +```
@@ -150,17 +150,18 @@ To create the necessary database secrets, execute the following command:
Required Secrets -````yaml +```yaml kubectl create secret generic db-encryption \ --from-literal=db-encryption-key='' \ --namespace homarr -```` +``` -````yaml +```yaml kubectl create secret generic db-secret \ --from-literal=db-url='mysql://user:password@host:port/homarrdb' \ --namespace homarr -```` +``` +
Below is an example of the override values file: @@ -168,10 +169,11 @@ Below is an example of the override values file:
values.yaml -````yaml +```yaml database: type: mysql -```` +``` +
#### External Postgresql database @@ -181,17 +183,17 @@ To create the necessary database secrets, execute the following command:
Required Secrets -````yaml +```yaml kubectl create secret generic db-encryption \ --from-literal=db-encryption-key='' \ --namespace homarr -```` +``` -````yaml +```yaml kubectl create secret generic db-secret \ --from-literal=db-url='postgresql://user:password@host:port/homarrdb' \ --namespace homarr -```` +```
@@ -200,10 +202,11 @@ Below is an example of the override values file:
values.yaml -````yaml +```yaml database: type: postgresql -```` +``` +
### Ingress @@ -213,7 +216,7 @@ The ingress section in the values.yaml file allows you to configure how external
values.yaml -````yaml +```yaml service: enabled: true # Ensure the service is enabled for Ingress to route traffic ingress: @@ -231,7 +234,8 @@ ingress: - "homarr.homelab.dev" - "www.homarr.homelab.dev" secretName: homelab-tls -```` +``` +
### HTTPRoute (Gateway API) @@ -242,9 +246,9 @@ This provides a more expressive and future-proof alternative to Ingress, with su
values.yaml -````yaml +```yaml service: - enabled: true # must be enabled for HTTPRoute to forward traffic + enabled: true # must be enabled for HTTPRoute to forward traffic httproute: enabled: true parentRefs: @@ -268,7 +272,7 @@ httproute: - parentRefs: the Gateway(s) this route attaches to. Gateways must already exist. - hostnames: domain names this route applies to. -- rules: each rule can define matches (paths, headers, queries), optional filters, and backendRefs to services +- rules: each rule can define matches (paths, headers, queries), optional filters, and backendRefs to services - TLS must be configured on the Gateway (not on HTTPRoute). For example, the Gateway can have a TLS listener for homarr.homelab.dev, and this route will automatically apply once matched. ### Certificates @@ -285,7 +289,7 @@ Use inline certificates to generate a ConfigMap, mounted as individual files.
values.yaml -````yaml +```yaml persistence: homarrTrustedCerts: enabled: true @@ -299,7 +303,8 @@ persistence: -----BEGIN CERTIFICATE----- MIID...EFGH== -----END CERTIFICATE----- -```` +``` +
Behavior: @@ -314,7 +319,7 @@ Use inline certificates to generate a Kubernetes Secret, mounted as files.
values.yaml -````yaml +```yaml persistence: homarrTrustedCerts: enabled: true @@ -328,7 +333,8 @@ persistence: -----BEGIN CERTIFICATE----- MIIC...XYZ== -----END CERTIFICATE----- -```` +``` +
Behavior: @@ -343,16 +349,17 @@ Use an existing Kubernetes Secret, assuming its keys are filenames.
values.yaml -````yaml +```yaml persistence: homarrTrustedCerts: enabled: true type: existingSecret existingSecretName: "existingSecretName" existingSecretKeys: - - cert3.crt - - cert4.crt -```` + - cert3.crt + - cert4.crt +``` +
Behavior: @@ -483,4 +490,5 @@ All available values are listed on the [artifacthub](https://artifacthub.io/pack | tolerations | list | `[]` | Node tolerations for pod scheduling | --- + Autogenerated from chart metadata using [helm-docs](https://github.com/norwoodj/helm-docs) diff --git a/apps/docs/docs/getting-started/installation/home-assistant.mdx b/apps/docs/docs/getting-started/installation/home-assistant.mdx index 9f5a50f52..9ba9c5d01 100644 --- a/apps/docs/docs/getting-started/installation/home-assistant.mdx +++ b/apps/docs/docs/getting-started/installation/home-assistant.mdx @@ -14,7 +14,7 @@ Homarr can be seamlessly integrated into your Home Assistant setup with this add ## Installation 1. **Add Repository**: Navigate to your Home Assistant Supervisor panel, and go to the Add-on Store. Add the following repository URL: `https://github.com/Wiggen94/ha-homarr-v1-server` or click this button -[![Open your Home Assistant instance and show the add add-on repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2FWiggen94%2Fha-homarr-v1-server) + [![Open your Home Assistant instance and show the add add-on repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2FWiggen94%2Fha-homarr-v1-server) 2. **Install the Add-on**: Search for "Homarr Server" in the Add-on Store and select it. Click on "Install" to start the installation process. diff --git a/apps/docs/docs/getting-started/installation/portainer.mdx b/apps/docs/docs/getting-started/installation/portainer.mdx index f816d77fe..0442b215e 100644 --- a/apps/docs/docs/getting-started/installation/portainer.mdx +++ b/apps/docs/docs/getting-started/installation/portainer.mdx @@ -1,5 +1,7 @@ # Portainer + ## Portainer Stacks + ### Prerequisites - [Portainer Stacks](https://www.portainer.io/blog/stacks-docker-compose-the-portainer-way) @@ -23,15 +25,14 @@ services: environment: - SECRET_ENCRYPTION_KEY=your_64_character_hex_string # <--- can be generated with `openssl rand -hex 32` ports: - - '7575:7575' + - "7575:7575" ``` - :::note -Portainer will mount the files to your host machine. Please make sure to replace ```` from the docker run command with your desired storage location. The path must be absolute. +Portainer will mount the files to your host machine. Please make sure to replace `` from the docker run command with your desired storage location. The path must be absolute. ::: -Then, click on ``Deploy the stack`` and wait until the container has started. +Then, click on `Deploy the stack` and wait until the container has started. :::tip @@ -43,5 +44,5 @@ If you're unsure how to create a stack, checkout the [Portainer Documentation](h To update Homarr using Docker Compose or Portainer Stacks, simply pull the latest image and restart the container. -1. Run ``docker pull ghcr.io/homarr-labs/homarr:latest`` to pull the latest image. -2. Re-run ``docker-compose up -d`` or re-deploy the stack in Portainer. +1. Run `docker pull ghcr.io/homarr-labs/homarr:latest` to pull the latest image. +2. Re-run `docker-compose up -d` or re-deploy the stack in Portainer. diff --git a/apps/docs/docs/getting-started/installation/proxmox.mdx b/apps/docs/docs/getting-started/installation/proxmox.mdx index f6f5fb120..bd33b4040 100644 --- a/apps/docs/docs/getting-started/installation/proxmox.mdx +++ b/apps/docs/docs/getting-started/installation/proxmox.mdx @@ -31,7 +31,7 @@ After you've installed Homarr, you can find a new LXC "homarr". # Updating -Updating is as simple as executing +Updating is as simple as executing ```bash update @@ -49,17 +49,19 @@ Some Homarr features require setting environment variables. When installing Homa # Troubleshooting -If something does not work after an update, please first try rebooting the LXC or the homarr Service with +If something does not work after an update, please first try rebooting the LXC or the homarr Service with ```bash systemctl restart homarr ``` # Getting help + - If you are looking for help with the script, updating the LXC or troubleshooting the installer, please get in contact with the support of the community scripts. They provide support on their [Discord](https://discord.gg/2wvnMDgdnU). If you found vulnerabilities, bugs or have a request for the script, [create a new issue here](https://github.com/community-scripts/ProxmoxVE/issues/new/choose). - If you are looking to report a bug, vulnerability or request a new feature, use https://github.com/homarr-labs/homarr . You can ask for help on our Discord. # How to find logs + Homarr runs under a system service called `homarr`, so getting the logs is a simple as using the following command inside the LXC (Container) Shell ```bash diff --git a/apps/docs/docs/getting-started/installation/qnap.mdx b/apps/docs/docs/getting-started/installation/qnap.mdx index a655db5b3..b8c1f977b 100644 --- a/apps/docs/docs/getting-started/installation/qnap.mdx +++ b/apps/docs/docs/getting-started/installation/qnap.mdx @@ -4,6 +4,6 @@ QNAP installation guide has not updated to 1.0 yet. There guide is still for 0.15.10. ::: -When installing on QNAP, we recommend you to install Homarr using [Container Station]( https://www.qnap.com/en/software/container-station) or [this third-party image](https://www.myqnap.org/product/homarr/). +When installing on QNAP, we recommend you to install Homarr using [Container Station](https://www.qnap.com/en/software/container-station) or [this third-party image](https://www.myqnap.org/product/homarr/). There is also a guide available, but note that it is written in Chinese: https://post.smzdm.com/p/awzm7op2/ diff --git a/apps/docs/docs/getting-started/installation/runtipi.mdx b/apps/docs/docs/getting-started/installation/runtipi.mdx index 53a669c90..c2b2823b7 100644 --- a/apps/docs/docs/getting-started/installation/runtipi.mdx +++ b/apps/docs/docs/getting-started/installation/runtipi.mdx @@ -1,4 +1,4 @@ -# Runtipi +# Runtipi Runtipi is a self-hosted orchestrator that makes it easy to manage and run multiple services on a single server. It is based on Docker and comes with a simple web interface to manage your services. Runtipi is designed to be easy to use, so you don't have to worry about manual configuration or networking. @@ -11,6 +11,7 @@ https://runtipi.io # Installation Installing Homarr is pretty untuitive, the app is available in the default appstore : + 1. Search for **"Homarr"** in the App-Store page and select it 2. Click on **"Install"**. 3. Choose the method you want to access Homarr, through any port or domain name then select **"Install"** @@ -18,13 +19,15 @@ Installing Homarr is pretty untuitive, the app is available in the default appst # Maintenance After installation, all you need is available from the WebUI in **"My apps"** > **"Homarr"** : - - Start/Stop - - Update - - Backup - - Logs - + +- Start/Stop +- Update +- Backup +- Logs + If you like to tinker with your apps, you can also edit your app's docker-compose with a [user-config](https://runtipi.io/docs/guides/customize-app-config). # Getting help + - If you are looking for help with anything in Runtipi. They provide support on their [Discord](https://discord.gg/Bu9qEPnHsc) and [forums](https://forums.runtipi.io/). If you found vulnerabilities or bugs, [create a new issue here](https://github.com/runtipi/runtipi-appstore/issues). -- If you are looking to report a bug, vulnerability or request a new feature for Homarr, use https://github.com/homarr-labs/homarr . You can ask for help on our Discord. \ No newline at end of file +- If you are looking to report a bug, vulnerability or request a new feature for Homarr, use https://github.com/homarr-labs/homarr . You can ask for help on our Discord. diff --git a/apps/docs/docs/getting-started/installation/saltbox.mdx b/apps/docs/docs/getting-started/installation/saltbox.mdx index 2f284d72b..88805eafb 100644 --- a/apps/docs/docs/getting-started/installation/saltbox.mdx +++ b/apps/docs/docs/getting-started/installation/saltbox.mdx @@ -5,6 +5,7 @@ Saltbox installation command has not updated to 1.0 yet. There command still run ::: You can also use this to install on Saltbox: + ```bash sb install sandbox-homarr -``` \ No newline at end of file +``` diff --git a/apps/docs/docs/getting-started/installation/source.mdx b/apps/docs/docs/getting-started/installation/source.mdx index 933b264dd..838f0d0a2 100644 --- a/apps/docs/docs/getting-started/installation/source.mdx +++ b/apps/docs/docs/getting-started/installation/source.mdx @@ -28,15 +28,29 @@ This method is only useful, when you want to develop on Homarr or extend it with ## Steps
    -
  1. Clone the Repository using git clone https://github.com/homarr-labs/homarr.git
  2. -
  3. Enter the created directory using cd homarr
  4. -
  5. Install all dependencies using pnpm install
  6. -
  7. Copy the `.env.example` file to `.env` and replace `DB_URL` with the full path you want to use for the sqlite database file. For example `DB_URL='/home/username/homarr/db.sqlite`
  8. -
  9. Replace `AUTH_SECRET` and `SECRET_ENCRYPTION_KEY` both with a secure random string by using `openssl rand -hex 32`
  10. +
  11. + Clone the Repository using git clone https://github.com/homarr-labs/homarr.git +
  12. +
  13. + Enter the created directory using cd homarr +
  14. +
  15. + Install all dependencies using pnpm install +
  16. +
  17. + Copy the `.env.example` file to `.env` and replace `DB_URL` with the full path you want to use for the sqlite + database file. For example `DB_URL='/home/username/homarr/db.sqlite` +
  18. +
  19. + Replace `AUTH_SECRET` and `SECRET_ENCRYPTION_KEY` both with a secure random string by using `openssl rand -hex 32` +
  20. Replace `CRON_JOB_API_KEY` with a secure random string by using `openssl rand -base64 32`
  21. Run `pnpm run db:migration:sqlite:run` and wait that it completes
  22. Build the source using `pnpm build`
  23. -
  24. Copy better-sqlite3.node files with `mkdir build` and `cp ./node_modules/better-sqlite3/build/Release/better_sqlite3.node ./build/better_sqlite3.node`
  25. +
  26. + Copy better-sqlite3.node files with `mkdir build` and `cp + ./node_modules/better-sqlite3/build/Release/better_sqlite3.node ./build/better_sqlite3.node` +
  27. Start a redis server using `redis-server`
  28. Run the server using `pnpm start`
  29. Open `http://localhost:3000` in your browser
  30. diff --git a/apps/docs/docs/getting-started/installation/unraid.mdx b/apps/docs/docs/getting-started/installation/unraid.mdx index 5fa7cc9b0..18588c5d4 100644 --- a/apps/docs/docs/getting-started/installation/unraid.mdx +++ b/apps/docs/docs/getting-started/installation/unraid.mdx @@ -1,5 +1,5 @@ -import Link from '@docusaurus/Link'; -import { IconDownload } from '@tabler/icons-react'; +import Link from "@docusaurus/Link"; +import { IconDownload } from "@tabler/icons-react"; # Unraid @@ -14,17 +14,17 @@ You can install Homarr directly from your Unraid Dashboard, no terminal required -
    +
    Install community applications plugin
    -
    -
    +
    +
    :::tip @@ -46,4 +46,3 @@ After you've installed the Community Apps Plugin, you can install Homarr from th After you've installed Homarr, you can find it under the tab "Docker". The official support thread is located [here](https://forums.unraid.net/topic/123478-support-smartphonelover-homarr/), but we prefer to communicate over GitHub and Discord instead. - diff --git a/apps/docs/docs/integrations/adguard-home/index.mdx b/apps/docs/docs/integrations/adguard-home/index.mdx index b4cb6cdb6..52b26f66f 100644 --- a/apps/docs/docs/integrations/adguard-home/index.mdx +++ b/apps/docs/docs/integrations/adguard-home/index.mdx @@ -1,37 +1,44 @@ --- -title: 'AdGuard Home' +title: "AdGuard Home" description: "AdGuard Home is a network-wide software for blocking ads and trackers, providing a safer and faster internet experience." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconAd, IconDeviceGamepad } from "@tabler/icons-react"; -import { adguardHomeIntegration } from '.'; -import { dnsHoleSummaryWidget } from '@site/docs/widgets/dns-hole-summary'; -import { dnsHoleControlsWidget } from '@site/docs/widgets/dns-hole-controls'; +import { adguardHomeIntegration } from "."; +import { dnsHoleSummaryWidget } from "@site/docs/widgets/dns-hole-summary"; +import { dnsHoleControlsWidget } from "@site/docs/widgets/dns-hole-controls"; - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/anchor/index.mdx b/apps/docs/docs/integrations/anchor/index.mdx index e4d897767..2e43195cc 100644 --- a/apps/docs/docs/integrations/anchor/index.mdx +++ b/apps/docs/docs/integrations/anchor/index.mdx @@ -1,40 +1,45 @@ --- -title: 'Anchor' +title: "Anchor" description: "Anchor is a self-hosted note-taking application." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { anchorIntegration } from '.'; -import { anchorNoteWidget } from '@site/docs/widgets/anchor-note'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { anchorIntegration } from "."; +import { anchorNoteWidget } from "@site/docs/widgets/anchor-note"; - - + The Anchor integration lets Homarr connect to your Anchor instance so you can display and edit selected notes directly from your dashboard. ### Widgets & Capabilities + ### Adding the integration + ### Secrets - + + diff --git a/apps/docs/docs/integrations/aria2/index.mdx b/apps/docs/docs/integrations/aria2/index.mdx index 9950fec2f..8ec92a5d0 100644 --- a/apps/docs/docs/integrations/aria2/index.mdx +++ b/apps/docs/docs/integrations/aria2/index.mdx @@ -1,38 +1,43 @@ --- -title: 'Aria2' +title: "Aria2" description: "Lightweight multiprotocol & multi-source command-line download utility. It supports HTTP/HTTPS, FTP, SFTP, BitTorrent and Metalink" hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { aria2Integration } from '.'; -import { downloadsWidget } from '@site/docs/widgets/downloads'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { aria2Integration } from "."; +import { downloadsWidget } from "@site/docs/widgets/downloads"; - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/audiobookshelf/index.mdx b/apps/docs/docs/integrations/audiobookshelf/index.mdx index 156525ba5..a052d2fff 100644 --- a/apps/docs/docs/integrations/audiobookshelf/index.mdx +++ b/apps/docs/docs/integrations/audiobookshelf/index.mdx @@ -1,41 +1,40 @@ --- -title: 'Audiobookshelf' +title: "Audiobookshelf" description: "Audiobookshelf is a self-hosted audiobook and podcast server that lets you manage and stream your audio library." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { audiobookshelfIntegration } from '.'; -import { audioStatsWidget } from '@site/docs/widgets/audio-stats'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { audiobookshelfIntegration } from "."; +import { audioStatsWidget } from "@site/docs/widgets/audio-stats"; - - + Audiobookshelf provides library statistics including audiobook and podcast counts, listening time, and active sessions. ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - + + diff --git a/apps/docs/docs/integrations/bazarr/index.mdx b/apps/docs/docs/integrations/bazarr/index.mdx index f9400a45e..7e1ad2d64 100644 --- a/apps/docs/docs/integrations/bazarr/index.mdx +++ b/apps/docs/docs/integrations/bazarr/index.mdx @@ -1,31 +1,30 @@ --- -title: 'Bazarr' +title: "Bazarr" description: "Bazarr is a companion application to Sonarr and Radarr that manages and downloads subtitles." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { bazarrIntegration } from '.'; -import { bazarrWidget } from '@site/docs/widgets/bazarr'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { bazarrIntegration } from "."; +import { bazarrWidget } from "@site/docs/widgets/bazarr"; - + Bazarr complements Sonarr and Radarr by managing subtitle downloads. The Homarr integration uses your Bazarr API key to fetch missing subtitle counts and health badges. ### Screenshots -import apiKeySettings from './img/api-key-settings.png'; -import widgetOverview from '@site/docs/widgets/bazarr/img/widget-overview.png'; +import apiKeySettings from "./img/api-key-settings.png"; +import widgetOverview from "@site/docs/widgets/bazarr/img/widget-overview.png";
    -

    API key location in Bazarr (Settings → General → Security):

    +

    + API key location in Bazarr (Settings → General → Security): +

    bazarr-api-key-settings
    @@ -35,20 +34,25 @@ import widgetOverview from '@site/docs/widgets/bazarr/img/widget-overview.png';
    ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets + You can find your Bazarr API key under **Settings → General → Security**. - + diff --git a/apps/docs/docs/integrations/beszel/index.mdx b/apps/docs/docs/integrations/beszel/index.mdx index 0c93cdc9f..8ddda77c6 100644 --- a/apps/docs/docs/integrations/beszel/index.mdx +++ b/apps/docs/docs/integrations/beszel/index.mdx @@ -1,25 +1,22 @@ --- -title: 'Beszel' +title: "Beszel" description: "Beszel is a lightweight server monitoring platform with Docker stats, historical data, and alert functions." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { beszelIntegration } from '.'; -import { beszelSystemStatsWidget } from '@site/docs/widgets/beszel-system-stats'; -import { beszelSystemGridWidget } from '@site/docs/widgets/beszel-system-grid'; -import { beszelSystemTableWidget } from '@site/docs/widgets/beszel-system-table'; -import { beszelAlertsWidget } from '@site/docs/widgets/beszel-alerts'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { beszelIntegration } from "."; +import { beszelSystemStatsWidget } from "@site/docs/widgets/beszel-system-stats"; +import { beszelSystemGridWidget } from "@site/docs/widgets/beszel-system-grid"; +import { beszelSystemTableWidget } from "@site/docs/widgets/beszel-system-table"; +import { beszelAlertsWidget } from "@site/docs/widgets/beszel-alerts"; -import beszelDashboard from './img/beszel-dashboard.png'; +import beszelDashboard from "./img/beszel-dashboard.png"; - + Beszel monitors your servers in real time via lightweight agents, collecting CPU, memory, disk, network, GPU, temperature, and Docker container metrics. It stores historical data and supports configurable alerts. @@ -28,26 +25,33 @@ Beszel monitors your servers in real time via lightweight agents, collecting CPU Beszel dashboard overview showing all four widgets ### Widgets & Capabilities + ### Adding the integration + ### Secrets - + + :::tip Beszel uses PocketBase under the hood. The default admin credentials are set during the initial Beszel setup. diff --git a/apps/docs/docs/integrations/coolify/index.mdx b/apps/docs/docs/integrations/coolify/index.mdx index 56e5e6c29..7b828cc18 100644 --- a/apps/docs/docs/integrations/coolify/index.mdx +++ b/apps/docs/docs/integrations/coolify/index.mdx @@ -1,29 +1,24 @@ --- -title: 'Coolify' -description: 'Self-hosted PaaS and deployment platform' +title: "Coolify" +description: "Self-hosted PaaS and deployment platform" hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { coolifyIntegration } from '.'; -import { coolifyWidget } from '../../widgets/coolify'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { coolifyIntegration } from "."; +import { coolifyWidget } from "../../widgets/coolify"; - + ### Widgets & Capabilities - + + ### Adding the integration + :::info URL configuration @@ -31,16 +26,28 @@ Use the root URL of your Coolify instance, for example `https://coolify.example. ::: ### Secrets -Enable API access under Settings > Advanced if it is disabled.), - (Go to Security > API Tokens.), - 'Enter a name, e.g. "Homarr".', - (Select the read permission. The Coolify widget only reads version, server, project, application, and service data.), - 'Click "Create".', - 'Copy the generated token immediately. Coolify only shows it once.', - 'Paste the token into the API Key field in Homarr.' - ] -}]} /> + + + Enable API access under Settings > Advanced if it is disabled. + , + + Go to Security > API Tokens. + , + 'Enter a name, e.g. "Homarr".', + + Select the read permission. The Coolify widget only reads version, server, project, application, + and service data. + , + 'Click "Create".', + "Copy the generated token immediately. Coolify only shows it once.", + "Paste the token into the API Key field in Homarr.", + ], + }, + ]} +/> diff --git a/apps/docs/docs/integrations/dash-dot/index.mdx b/apps/docs/docs/integrations/dash-dot/index.mdx index 512bc6c8d..9c400321c 100644 --- a/apps/docs/docs/integrations/dash-dot/index.mdx +++ b/apps/docs/docs/integrations/dash-dot/index.mdx @@ -1,32 +1,33 @@ --- -title: 'Dash.' +title: "Dash." description: "Dash. is a system performance and resource monitoring tool" hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconHeartRateMonitor } from "@tabler/icons-react"; -import { dashDotIntegration } from '.'; -import { healthMonitoringWidget } from '@site/docs/widgets/health-monitoring'; -import { systemResourcesWidget } from '@site/docs/widgets/system-resources'; +import { dashDotIntegration } from "."; +import { healthMonitoringWidget } from "@site/docs/widgets/health-monitoring"; +import { systemResourcesWidget } from "@site/docs/widgets/system-resources"; - - + ### Widgets & Capabilities + ### Adding the integration - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/deluge/index.mdx b/apps/docs/docs/integrations/deluge/index.mdx index 24aadb910..89f906c0c 100644 --- a/apps/docs/docs/integrations/deluge/index.mdx +++ b/apps/docs/docs/integrations/deluge/index.mdx @@ -1,36 +1,41 @@ --- -title: 'Deluge' +title: "Deluge" description: "Deluge is a lightweight, Free Software, cross-platform BitTorrent client." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconDownload } from "@tabler/icons-react"; -import Alert from '@theme/Admonition'; -import { delugeIntegration } from '.'; -import { downloadsWidget } from '@site/docs/widgets/downloads'; +import Alert from "@theme/Admonition"; +import { delugeIntegration } from "."; +import { downloadsWidget } from "@site/docs/widgets/downloads"; - - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/docker/index.mdx b/apps/docs/docs/integrations/docker/index.mdx index 2af43c67e..40ade4912 100644 --- a/apps/docs/docs/integrations/docker/index.mdx +++ b/apps/docs/docs/integrations/docker/index.mdx @@ -1,32 +1,31 @@ --- -title: 'Docker' +title: "Docker" description: "Docker is a platform where you can run your applications in containers, allowing for easy deployment and management of applications." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconBrandDocker, IconTool } from "@tabler/icons-react"; -import { dockerIntegration } from '.'; -import { dockerContainersWidget } from '@site/docs/widgets/docker-containers'; +import { dockerIntegration } from "."; +import { dockerContainersWidget } from "@site/docs/widgets/docker-containers"; - - + ### Widgets & Capabilities + - ## Enabling the Docker integration + This integration must first be enabled. If you directly run on the host system and you have docker installed, it will be enabled by default. Otherwise, you'll need to mount the [docker socket](https://docs.docker.com/engine/security/protect-access/) to the Homarr container, @@ -49,7 +48,7 @@ services: environment: - SECRET_ENCRYPTION_KEY=your_64_character_hex_string # <--- can be generated with `openssl rand -hex 32` ports: - - '7575:7575' + - "7575:7575" ``` With docker run, add this parameter: `-v /var/run/docker.sock:/var/run/docker.sock`. @@ -124,8 +123,10 @@ services: ``` ### Managing your Docker containers within Homarr + Homarr allows you to interact with Docker containers running on your system. Each container row has an action menu with the following options: + - **View logs** - opens a dedicated logs page with a live terminal - **Start** - start a stopped container - **Stop** - stop a running container @@ -166,11 +167,13 @@ Currently Homarr supports one label for configuration of the containers: - **homarr.hide:** If set to any value, the container will be hidden from the Docker Containers widget and tools page. ### Security + Mounting docker sockets can be risky, as they permit full control over your docker service. As an example, a thread actor could abuse Homarr use the socket to start, stop or delete containers on your system. Therefore we recommend the usage of a socket proxy, which can prohibit certain actions. A few examples include: + - https://github.com/linuxserver/docker-socket-proxy - https://github.com/Tecnativa/docker-socket-proxy @@ -178,36 +181,44 @@ See documentation of the respective proxies on how to configure them. Homarr may behave in unexpected ways when you use proxies. #### Permissions + Homarr needs the following permissions from the Docker API: + - Containers/Start - Containers/Stop - Containers/Restart - Containers/Remove For socket proxies, you will need these permissions: + - `CONTAINERS=1` - `POST=1` **Caution:** `POST` access is security critical as it provides extensive capabilities to modify your docker environment. Please leave it disabled if you're concerned about this. As a workaround, you can use [LSIO's socket proxy](https://github.com/linuxserver/docker-socket-proxy) and set the following: + - ALLOW_START=1 - ALLOW_STOP=1 - ALLOW_RESTARTS=1 -These will work even with `POST=0`. +These will work even with `POST=0`. You lose the ability to remove containers, but start, stop and restarts should work just fine. #### Connecting to Docker via Socket Proxies + To connect to Docker via a socket proxy, you'll need to add these two environment variables in the compose file: + - `DOCKER_HOSTNAMES=` - `DOCKER_PORTS=` Refer: https://homarr.dev/docs/advanced/environment-variables/ You will also need to add Homarr to the network of your socket proxy. You can do it like this: + 1. Add the network to your compose file (with appropriate changes): + ```yaml networks: socket-proxy: @@ -216,6 +227,7 @@ networks: ``` 2. Add the network to the homarr service in the compose file: + ```yaml networks: - socket-proxy diff --git a/apps/docs/docs/integrations/emby/index.mdx b/apps/docs/docs/integrations/emby/index.mdx index 907d2bd96..2426a1561 100644 --- a/apps/docs/docs/integrations/emby/index.mdx +++ b/apps/docs/docs/integrations/emby/index.mdx @@ -1,37 +1,35 @@ --- -title: 'Emby' +title: "Emby" description: "Emby is a media server platform that allows you to organize, manage, and stream your personal media collection." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconVideo, IconTicket } from "@tabler/icons-react"; -import { embyIntegration } from '.'; -import { mediaServerWidget } from '@site/docs/widgets/media-server'; -import { mediaReleasesWidget } from '@site/docs/widgets/media-releases'; +import { embyIntegration } from "."; +import { mediaServerWidget } from "@site/docs/widgets/media-server"; +import { mediaReleasesWidget } from "@site/docs/widgets/media-releases"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/glances/index.mdx b/apps/docs/docs/integrations/glances/index.mdx index 2639f87e5..bd047e81d 100644 --- a/apps/docs/docs/integrations/glances/index.mdx +++ b/apps/docs/docs/integrations/glances/index.mdx @@ -1,37 +1,43 @@ --- -title: 'Glances' +title: "Glances" description: "Glances is a cross-platform system monitoring tool." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { glancesIntegration } from '.'; -import { systemResourcesWidget } from '@site/docs/widgets/system-resources'; -import { healthMonitoringWidget } from '@site/docs/widgets/health-monitoring'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { glancesIntegration } from "."; +import { systemResourcesWidget } from "@site/docs/widgets/system-resources"; +import { healthMonitoringWidget } from "@site/docs/widgets/health-monitoring"; - - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/gluetun/index.mdx b/apps/docs/docs/integrations/gluetun/index.mdx index 7c936fc1f..dca490781 100644 --- a/apps/docs/docs/integrations/gluetun/index.mdx +++ b/apps/docs/docs/integrations/gluetun/index.mdx @@ -1,20 +1,17 @@ --- -title: 'Gluetun' -description: 'Connect Gluetun to Homarr as a VPN integration.' +title: "Gluetun" +description: "Connect Gluetun to Homarr as a VPN integration." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { gluetunIntegration } from '.'; -import { vpnWidget } from '@site/docs/widgets/vpn'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { gluetunIntegration } from "."; +import { vpnWidget } from "@site/docs/widgets/vpn"; - + [Gluetun](https://github.com/qdm12/gluetun) exposes a control server that Homarr can query to report the VPN tunnel status, DNS status, public IP address, and active provider details in the VPN widget. @@ -22,9 +19,11 @@ status, DNS status, public IP address, and active provider details in the VPN wi ### Widgets & Capabilities ### Setting up the Gluetun control server @@ -40,13 +39,20 @@ Refer to the [Gluetun control server documentation](https://github.com/qdm12/glu Gluetun's control server can be left unprotected or secured with either an API key or HTTP Basic authentication. Choose the option that matches how your Gluetun instance integration is set up. - + diff --git a/apps/docs/docs/integrations/gotify/index.mdx b/apps/docs/docs/integrations/gotify/index.mdx index 09c81265b..43cde77b0 100644 --- a/apps/docs/docs/integrations/gotify/index.mdx +++ b/apps/docs/docs/integrations/gotify/index.mdx @@ -1,33 +1,39 @@ --- -title: 'Gotify' +title: "Gotify" description: "Gotify is a simple, self-hosted server for sending and receiving messages in real time." hide_title: true --- -import { notificationsWidget } from '@site/docs/widgets/notifications'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { gotifyIntegration } from '.'; +import { notificationsWidget } from "@site/docs/widgets/notifications"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { gotifyIntegration } from "."; - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - + + diff --git a/apps/docs/docs/integrations/home-assistant/index.mdx b/apps/docs/docs/integrations/home-assistant/index.mdx index 98ad591d6..65d09d166 100644 --- a/apps/docs/docs/integrations/home-assistant/index.mdx +++ b/apps/docs/docs/integrations/home-assistant/index.mdx @@ -1,45 +1,51 @@ --- -title: 'Home Assistant' +title: "Home Assistant" description: "Home Assistant is an open-source home automation platform that focuses on privacy and local control, allowing you to automate and control your smart home devices." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconBinaryTree } from "@tabler/icons-react"; -import { homeAssistantIntegration } from '.'; -import { smartHomeEntityStateWidget } from '@site/docs/widgets/smart-home-entity-state'; -import { smartHomeExecuteAutomationWidget } from '@site/docs/widgets/smart-home-execute-automation'; +import { homeAssistantIntegration } from "."; +import { smartHomeEntityStateWidget } from "@site/docs/widgets/smart-home-entity-state"; +import { smartHomeExecuteAutomationWidget } from "@site/docs/widgets/smart-home-execute-automation"; - - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + ], + }, + ]} +/> diff --git a/apps/docs/docs/integrations/ical/index.mdx b/apps/docs/docs/integrations/ical/index.mdx index 5f5ffc422..475229a34 100644 --- a/apps/docs/docs/integrations/ical/index.mdx +++ b/apps/docs/docs/integrations/ical/index.mdx @@ -1,38 +1,44 @@ --- -title: 'iCal' +title: "iCal" description: "iCal is a standard for calendar data exchange, allowing users to share and manage calendar events across different platforms." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconZoomQuestion, IconChartBar, IconSearch } from "@tabler/icons-react"; -import { icalIntegration } from '.'; -import { calendarWidget } from '@site/docs/widgets/calendar'; +import { icalIntegration } from "."; +import { calendarWidget } from "@site/docs/widgets/calendar"; - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - + + ## Using the iCal integration -The iCal integration allows you to add external calendars to Homarr. Any calendar that provides a public iCal URL can be integrated, such as Google Calendar, Apple Calendar, or Outlook. \ No newline at end of file +The iCal integration allows you to add external calendars to Homarr. Any calendar that provides a public iCal URL can be integrated, such as Google Calendar, Apple Calendar, or Outlook. diff --git a/apps/docs/docs/integrations/immich/index.mdx b/apps/docs/docs/integrations/immich/index.mdx index b887e5bb9..efe4c5106 100644 --- a/apps/docs/docs/integrations/immich/index.mdx +++ b/apps/docs/docs/integrations/immich/index.mdx @@ -1,36 +1,29 @@ --- -title: 'Immich' +title: "Immich" description: "Self-hosted photo and video management solution" hide_title: true --- -import { immichAlbumCarouselWidget } from '../../widgets/immich-album-carousel';import { - IntegrationHeader -} from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { immichIntegration } from '.'; -import { immichServerStatsWidget } from '../../widgets/immich-server-stats'; +import { immichAlbumCarouselWidget } from "../../widgets/immich-album-carousel"; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { immichIntegration } from "."; +import { immichServerStatsWidget } from "../../widgets/immich-server-stats"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets + ), - 'Create the integration in Homarr and copy the API key to there' - ] +'Create the integration in Homarr and copy the API key to there' +] }]} /> diff --git a/apps/docs/docs/integrations/jellyfin/index.mdx b/apps/docs/docs/integrations/jellyfin/index.mdx index 4826386b8..83e23fd45 100644 --- a/apps/docs/docs/integrations/jellyfin/index.mdx +++ b/apps/docs/docs/integrations/jellyfin/index.mdx @@ -1,40 +1,39 @@ --- -title: 'Jellyfin' +title: "Jellyfin" description: "Jellyfin is a free and open-source media server software that allows you to organize, manage, and share your media files." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconVideo, IconTicket } from "@tabler/icons-react"; -import { jellyfinIntegration } from '.'; -import { mediaServerWidget } from '@site/docs/widgets/media-server'; -import { mediaReleasesWidget } from '@site/docs/widgets/media-releases'; +import { jellyfinIntegration } from "."; +import { mediaServerWidget } from "@site/docs/widgets/media-server"; +import { mediaReleasesWidget } from "@site/docs/widgets/media-releases"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/jellyseerr/index.mdx b/apps/docs/docs/integrations/jellyseerr/index.mdx index a85d7bd9f..e752906bb 100644 --- a/apps/docs/docs/integrations/jellyseerr/index.mdx +++ b/apps/docs/docs/integrations/jellyseerr/index.mdx @@ -1,45 +1,52 @@ --- -title: 'Jellyseerr' +title: "Jellyseerr" description: "Jellyseerr is a self-hosted media request management system that integrates with Jellyfin and other media servers." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconZoomQuestion, IconChartBar, IconSearch } from "@tabler/icons-react"; -import { jellyseerrIntegration } from '.'; -import { mediaRequestListWidget } from '@site/docs/widgets/media-request-list'; -import { mediaRequestStatsWidget } from '@site/docs/widgets/media-request-stats'; +import { jellyseerrIntegration } from "."; +import { mediaRequestListWidget } from "@site/docs/widgets/media-request-list"; +import { mediaRequestStatsWidget } from "@site/docs/widgets/media-request-stats"; - - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/kubernetes/index.mdx b/apps/docs/docs/integrations/kubernetes/index.mdx index 899c60931..662874467 100644 --- a/apps/docs/docs/integrations/kubernetes/index.mdx +++ b/apps/docs/docs/integrations/kubernetes/index.mdx @@ -1,20 +1,16 @@ --- -title: 'Kubernetes' +title: "Kubernetes" description: "Kubernetes is a powerful container orchestration platform that automates the deployment, scaling, and management of containerized applications." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconBrandDocker, IconTool } from "@tabler/icons-react"; -import { kubernetesIntegration } from '.'; +import { kubernetesIntegration } from "."; - - + Homarr provides a user-friendly Kubernetes dashboard that offers an overview of your cluster’s resources in a clear and structured interface. It allows users to view key Kubernetes objects, including `Pods`, `Services`, `Ingresses`, `Nodes`, `ConfigMaps`, `Secrets`, `Namespaces`, and `Volumes`, as well as basic metrics when the Kubernetes Metrics Server is enabled. @@ -47,7 +43,7 @@ Enabling RBAC in the Helm chart creates the necessary Kubernetes Role-Based Acce - Service Account: A dedicated service account for Homarr. - Role & RoleBinding: Grants permissions within a specific namespace to list, watch, and get pods, services, secrets, configmaps, and more. - ClusterRole & ClusterRoleBinding: Extends the same permissions cluster-wide for additional flexibility. -::: + ::: ### Homarr Dashboard Overview diff --git a/apps/docs/docs/integrations/lidarr/index.mdx b/apps/docs/docs/integrations/lidarr/index.mdx index 498503617..ad5916a3f 100644 --- a/apps/docs/docs/integrations/lidarr/index.mdx +++ b/apps/docs/docs/integrations/lidarr/index.mdx @@ -1,35 +1,40 @@ --- -title: 'Lidarr' +title: "Lidarr" description: "Lidarr is a music management tool that automates the process of downloading, sorting, and renaming music." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconCalendar } from "@tabler/icons-react"; -import { lidarrIntegration } from '.'; -import { calendarWidget } from '@site/docs/widgets/calendar'; +import { lidarrIntegration } from "."; +import { calendarWidget } from "@site/docs/widgets/calendar"; - - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/navidrome/index.mdx b/apps/docs/docs/integrations/navidrome/index.mdx index c2578afa0..d5b1993ad 100644 --- a/apps/docs/docs/integrations/navidrome/index.mdx +++ b/apps/docs/docs/integrations/navidrome/index.mdx @@ -1,5 +1,5 @@ --- -title: 'Navidrome' +title: "Navidrome" description: "Navidrome is a self-hosted music server and streamer compatible with the Subsonic API." hide_title: true --- @@ -21,13 +21,19 @@ Navidrome provides music library statistics including artist, album, and song co ### Adding the integration + ### Secrets - + + diff --git a/apps/docs/docs/integrations/nextcloud/index.mdx b/apps/docs/docs/integrations/nextcloud/index.mdx index ba5ab8ee9..f7d7e05fa 100644 --- a/apps/docs/docs/integrations/nextcloud/index.mdx +++ b/apps/docs/docs/integrations/nextcloud/index.mdx @@ -1,40 +1,43 @@ --- -title: 'Nextcloud' +title: "Nextcloud" description: "Nextcloud is a self-hosted productivity platform that provides file storage, collaboration tools, and more." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconCalendar } from "@tabler/icons-react"; -import Alert from '@theme/Admonition'; -import { nextcloudIntegration } from '.'; -import { calendarWidget } from '@site/docs/widgets/calendar'; -import { notificationsWidget } from '@site/docs/widgets/notifications'; +import Alert from "@theme/Admonition"; +import { nextcloudIntegration } from "."; +import { calendarWidget } from "@site/docs/widgets/calendar"; +import { notificationsWidget } from "@site/docs/widgets/notifications"; - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - - Users who use 2FA will have to use Nextcloud's App Password tool to grant Homarr access, as 2FA breaks the traditional process. For more information, see [Nextcloud's Documentation](https://docs.nextcloud.com/server/stable/admin_manual/configuration_user/authentication.html#app-passwords) - , -}]} /> + + + Users who use 2FA will have to use Nextcloud's App Password tool to grant Homarr access, as 2FA breaks the + traditional process. For more information, see [Nextcloud's + Documentation](https://docs.nextcloud.com/server/stable/admin_manual/configuration_user/authentication.html#app-passwords) + + ), + }, + ]} +/> diff --git a/apps/docs/docs/integrations/ntfy/index.mdx b/apps/docs/docs/integrations/ntfy/index.mdx index 4b21d16a4..a132de923 100644 --- a/apps/docs/docs/integrations/ntfy/index.mdx +++ b/apps/docs/docs/integrations/ntfy/index.mdx @@ -1,37 +1,44 @@ --- -title: 'Ntfy' +title: "Ntfy" description: "Ntfy is a simple, open-source notification service that allows you to send and receive notifications across devices." hide_title: true --- -import { notificationsWidget } from '@site/docs/widgets/notifications'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; +import { notificationsWidget } from "@site/docs/widgets/notifications"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; import { IconMessage } from "@tabler/icons-react"; -import { ntfyIntegration } from '.'; +import { ntfyIntegration } from "."; - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/nzbget/index.mdx b/apps/docs/docs/integrations/nzbget/index.mdx index 3479f317a..1b7c23a1f 100644 --- a/apps/docs/docs/integrations/nzbget/index.mdx +++ b/apps/docs/docs/integrations/nzbget/index.mdx @@ -1,36 +1,41 @@ --- -title: 'NZBGet' +title: "NZBGet" description: "NZBGet is a lightweight and efficient Usenet downloader." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconDownload } from "@tabler/icons-react"; -import { nzbgetIntegration } from '.'; -import Alert from '@theme/Admonition'; -import { downloadsWidget } from '@site/docs/widgets/downloads'; +import { nzbgetIntegration } from "."; +import Alert from "@theme/Admonition"; +import { downloadsWidget } from "@site/docs/widgets/downloads"; - - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/open-media-vault/index.mdx b/apps/docs/docs/integrations/open-media-vault/index.mdx index ac0a42290..b934bf797 100644 --- a/apps/docs/docs/integrations/open-media-vault/index.mdx +++ b/apps/docs/docs/integrations/open-media-vault/index.mdx @@ -1,42 +1,52 @@ --- -title: 'Open Media Vault' +title: "Open Media Vault" description: "Open Media Vault is a free network-attached storage server based on the Debian operating system." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconHeartRateMonitor } from "@tabler/icons-react"; -import { openMediaVaultIntegration } from '.'; -import Alert from '@theme/Admonition' -import { healthMonitoringWidget } from '@site/docs/widgets/health-monitoring'; -import { systemResourcesWidget } from '@site/docs/widgets/system-resources'; +import { openMediaVaultIntegration } from "."; +import Alert from "@theme/Admonition"; +import { healthMonitoringWidget } from "@site/docs/widgets/health-monitoring"; +import { systemResourcesWidget } from "@site/docs/widgets/system-resources"; - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - - The user used here must have administrative permissions or Homarr won't be able to read the system performance and resource data. - -}]} /> \ No newline at end of file + + + The user used here must have administrative permissions or Homarr won't be able to read the system performance + and resource data. + + ), + }, + ]} +/> diff --git a/apps/docs/docs/integrations/opnsense/index.mdx b/apps/docs/docs/integrations/opnsense/index.mdx index 37e9a78c6..9a3a2b1ee 100644 --- a/apps/docs/docs/integrations/opnsense/index.mdx +++ b/apps/docs/docs/integrations/opnsense/index.mdx @@ -1,65 +1,75 @@ --- -title: 'OPNsense' +title: "OPNsense" description: "OPNsense is an open-source, easy-to-use, and easy-to-build firewall and routing platform." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconHeartRateMonitor } from "@tabler/icons-react"; -import { opnsenseIntegration } from '.'; -import Alert from '@theme/Admonition' -import { firewallWidget } from '../../widgets/firewall'; +import { opnsenseIntegration } from "."; +import Alert from "@theme/Admonition"; +import { firewallWidget } from "../../widgets/firewall"; - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - - This integration does not require full API access to the firewall. The following guide outlines the process for creating a restricted OPNsense user with a scrambled password, designed exclusively for API access. This ensures minimal permissions and prevents local login capability. - , - steps: [ + + + This integration does not require full API access to the firewall. The following guide outlines the process + for creating a restricted OPNsense user with a scrambled password, designed exclusively for API access. This + ensures minimal permissions and prevents local login capability. + + ), + steps: [ "Log in to the OPNsense web interface as an administrator", "Navigate to System → Access → Users", "Click the + (Add) button to create a new user", <> - Fill in the user details: -
      -
    • Username: Enter a unique name
    • -
    • Password: Leave empty
    • -
    • Scrambled Password: Enable this option
    • -
    • Full name: (Optional) Add a descriptive name
    • -
    + Fill in the user details: +
      +
    • Username: Enter a unique name
    • +
    • Password: Leave empty
    • +
    • Scrambled Password: Enable this option
    • +
    • Full name: (Optional) Add a descriptive name
    • +
    , <> - In Privileges section → Select the option below: -
      -
    • Lobby: Dashboard
    • -
    • Reporting: Traffic
    • -
    + In Privileges section → Select the option below: +
      +
    • Lobby: Dashboard
    • +
    • Reporting: Traffic
    • +
    , "Click Save", "Return to the Users list", "Find the user and click the ticket icon in the Commands column", "Click Yes in the popup to confirm", "A txt file will download automatically, containing: Key and Secret", - "Save this file securely—this information will only be shown once" - ], -}]} /> \ No newline at end of file + "Save this file securely—this information will only be shown once", + ], + }, + ]} +/> diff --git a/apps/docs/docs/integrations/overseerr/index.mdx b/apps/docs/docs/integrations/overseerr/index.mdx index ce9e0a3e5..2dd2d7c8a 100644 --- a/apps/docs/docs/integrations/overseerr/index.mdx +++ b/apps/docs/docs/integrations/overseerr/index.mdx @@ -1,45 +1,52 @@ --- -title: 'Overseerr' +title: "Overseerr" description: "Overseerr is a self-hosted media request management system that integrates with Plex." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconZoomQuestion, IconChartBar, IconSearch } from "@tabler/icons-react"; -import { overseerrIntegration } from '.'; -import { mediaRequestListWidget } from '@site/docs/widgets/media-request-list'; -import { mediaRequestStatsWidget } from '@site/docs/widgets/media-request-stats'; +import { overseerrIntegration } from "."; +import { mediaRequestListWidget } from "@site/docs/widgets/media-request-list"; +import { mediaRequestStatsWidget } from "@site/docs/widgets/media-request-stats"; - - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/paperless-ngx/index.mdx b/apps/docs/docs/integrations/paperless-ngx/index.mdx index e08840110..175fdb15a 100644 --- a/apps/docs/docs/integrations/paperless-ngx/index.mdx +++ b/apps/docs/docs/integrations/paperless-ngx/index.mdx @@ -1,41 +1,40 @@ --- -title: 'Paperless-ngx' +title: "Paperless-ngx" description: "Paperless-ngx is a document management system that transforms your physical documents into a searchable online archive." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { paperlessNgxIntegration } from '.'; -import { paperlessNgxWidget } from '@site/docs/widgets/paperless-ngx'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { paperlessNgxIntegration } from "."; +import { paperlessNgxWidget } from "@site/docs/widgets/paperless-ngx"; - - + Paperless-ngx provides document statistics including total documents, inbox count, correspondents, tags, and document types. ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - + + diff --git a/apps/docs/docs/integrations/patchmon/index.mdx b/apps/docs/docs/integrations/patchmon/index.mdx index 95b827df0..b60c20962 100644 --- a/apps/docs/docs/integrations/patchmon/index.mdx +++ b/apps/docs/docs/integrations/patchmon/index.mdx @@ -1,43 +1,42 @@ --- -title: 'PatchMon' +title: "PatchMon" description: "PatchMon is a patch management and monitoring solution for Linux hosts." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { patchmonIntegration } from '.'; -import { patchmonWidget } from '@site/docs/widgets/patchmon'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { patchmonIntegration } from "."; +import { patchmonWidget } from "@site/docs/widgets/patchmon"; - - + PatchMon provides host and package update statistics including total hosts, hosts needing updates, and security update counts. The PatchMon widget requires users to be **signed in to Homarr**; see the [PatchMon widget documentation](/docs/widgets/patchmon#authentication) for details on authentication and public boards. ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - + + diff --git a/apps/docs/docs/integrations/peanut/index.mdx b/apps/docs/docs/integrations/peanut/index.mdx index 751200bed..7eb7b845b 100644 --- a/apps/docs/docs/integrations/peanut/index.mdx +++ b/apps/docs/docs/integrations/peanut/index.mdx @@ -1,48 +1,53 @@ --- -title: 'PeaNUT' -description: 'A tiny dashboard for Network UPS Tools (NUT) servers.' +title: "PeaNUT" +description: "A tiny dashboard for Network UPS Tools (NUT) servers." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { peaNutIntegration } from '.'; -import { upsWidget } from '@site/docs/widgets/ups'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { peaNutIntegration } from "."; +import { upsWidget } from "@site/docs/widgets/ups"; - + [PeaNUT](https://github.com/Brandawg93/PeaNUT) exposes the data of your [Network UPS Tools](https://networkupstools.org/) servers over a REST API, which Homarr reads to display the status of your UPS devices. ### Widgets & Capabilities + ### Adding the integration + ### Secrets + PeaNUT secures its API with HTTP Basic authentication when the `WEB_USERNAME` and `WEB_PASSWORD` environment variables are set on the PeaNUT instance. Provide the same credentials here. If the instance runs with `AUTH_DISABLED=true`, no secrets are required. - + diff --git a/apps/docs/docs/integrations/pi-hole/index.mdx b/apps/docs/docs/integrations/pi-hole/index.mdx index ca2b400e7..d724b026d 100644 --- a/apps/docs/docs/integrations/pi-hole/index.mdx +++ b/apps/docs/docs/integrations/pi-hole/index.mdx @@ -1,47 +1,54 @@ --- -title: 'Pi-hole' +title: "Pi-hole" description: "Pi-hole is a network-wide ad blocker that acts as a DNS sinkhole, blocking unwanted content and improving your browsing experience." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconAd, IconDeviceGamepad } from "@tabler/icons-react"; -import Alert from '@theme/Admonition'; -import { dnsHoleSummaryWidget } from '@site/docs/widgets/dns-hole-summary'; -import { dnsHoleControlsWidget } from '@site/docs/widgets/dns-hole-controls'; -import { piHoleIntegration } from '.'; +import Alert from "@theme/Admonition"; +import { dnsHoleSummaryWidget } from "@site/docs/widgets/dns-hole-summary"; +import { dnsHoleControlsWidget } from "@site/docs/widgets/dns-hole-controls"; +import { piHoleIntegration } from "."; + - - - - Homarr supports both Pi-hole v5 and v6. It automatically detects the version and uses the correct API. + + Homarr supports both Pi-hole v5 and v6. It automatically detects the version and uses the correct API. ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/plex/index.mdx b/apps/docs/docs/integrations/plex/index.mdx index b6394b918..b6e35a6e3 100644 --- a/apps/docs/docs/integrations/plex/index.mdx +++ b/apps/docs/docs/integrations/plex/index.mdx @@ -1,41 +1,47 @@ --- -title: 'Plex' +title: "Plex" description: "Plex is a media server platform that allows you to organize, manage, and stream your personal media collection." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconVideo, IconTicket } from "@tabler/icons-react"; -import { plexIntegration } from '.'; -import { mediaServerWidget } from '@site/docs/widgets/media-server'; -import { mediaReleasesWidget } from '@site/docs/widgets/media-releases'; +import { plexIntegration } from "."; +import { mediaServerWidget } from "@site/docs/widgets/media-server"; +import { mediaReleasesWidget } from "@site/docs/widgets/media-releases"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - - Follow the official Plex documentation to find your authentication token. - - ] -}]} /> \ No newline at end of file + Follow the official{" "} + + Plex documentation + {" "} + to find your authentication token. + , + ], + }, + ]} +/> diff --git a/apps/docs/docs/integrations/prowlarr/index.mdx b/apps/docs/docs/integrations/prowlarr/index.mdx index 0c5561f91..b3624a97e 100644 --- a/apps/docs/docs/integrations/prowlarr/index.mdx +++ b/apps/docs/docs/integrations/prowlarr/index.mdx @@ -1,32 +1,34 @@ --- -title: 'Prowlarr' +title: "Prowlarr" description: "Prowlarr is an indexer manager for Usenet and BitTorrent, providing a unified interface to manage your indexers." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconHeartRateMonitor } from "@tabler/icons-react"; -import { prowlarrIntegration } from '.'; -import { indexerManagerWidget } from '@site/docs/widgets/indexer-manager'; +import { prowlarrIntegration } from "."; +import { indexerManagerWidget } from "@site/docs/widgets/indexer-manager"; - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/proxmox/index.mdx b/apps/docs/docs/integrations/proxmox/index.mdx index 4ea8eda98..f038dd007 100644 --- a/apps/docs/docs/integrations/proxmox/index.mdx +++ b/apps/docs/docs/integrations/proxmox/index.mdx @@ -1,103 +1,107 @@ --- -title: 'Proxmox' +title: "Proxmox" description: "Proxmox is a powerful open-source virtualization platform that allows you to run virtual machines and containers." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconHeartRateMonitor } from "@tabler/icons-react"; -import { proxmoxIntegration } from '.'; -import Alert from '@theme/Admonition' -import { healthMonitoringWidget } from '@site/docs/widgets/health-monitoring'; -import { systemResourcesWidget } from '@site/docs/widgets/system-resources'; +import { proxmoxIntegration } from "."; +import Alert from "@theme/Admonition"; +import { healthMonitoringWidget } from "@site/docs/widgets/health-monitoring"; +import { systemResourcesWidget } from "@site/docs/widgets/system-resources"; - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - - The Proxmox API may not work with Linux PAM standard authentication. It is strongly recommended to use the Proxmox VE authentication server realm when creating your API user. - , - credentials: ['username', 'tokenId', 'realm', 'apiKey'], - steps: [ + + + The Proxmox API may not work with Linux PAM standard authentication. It is strongly recommended to use the + Proxmox VE authentication server realm when creating your API user. + + ), + credentials: ["username", "tokenId", "realm", "apiKey"], + steps: [ "Navigate to the Proxmox portal, click on Datacenter", "Expand Permissions, click on Groups", "Click the Create button", "Name the group something informative, like api-users", "Click on the Permissions 'folder'", <> - Click Add {"->"} Group Permission -
      -
    • Path: /
    • -
    • Group: group from Step 4 above
    • -
    • Role: PVEAuditor
    • -
    • Propagate: Checked
    • -
    + Click Add {"->"} Group Permission +
      +
    • Path: /
    • +
    • Group: group from Step 4 above
    • +
    • Role: PVEAuditor
    • +
    • Propagate: Checked
    • +
    , "Expand Permissions, click on Users", <> - Click the Add button -
      -
    • User name: something informative like api
    • -
    • Realm: Proxmox VE authentication server
    • -
    • Password: create a secure password for the user
    • -
    • Confirm Password: re-enter the password
    • -
    • Group: group from Step 4 above
    • -
    + Click the Add button +
      +
    • User name: something informative like api
    • +
    • Realm: Proxmox VE authentication server
    • +
    • Password: create a secure password for the user
    • +
    • Confirm Password: re-enter the password
    • +
    • Group: group from Step 4 above
    • +
    , "Expand Permissions, click on API Tokens", <> - Click the Add button -
      -
    • User: user from Step 8 above
    • -
    • Token ID: something informative like the application or purpose like homarr
    • -
    • Privilege Separation: unchecked
    • -
    + Click the Add button +
      +
    • User: user from Step 8 above
    • +
    • Token ID: something informative like the application or purpose like homarr
    • +
    • Privilege Separation: unchecked
    • +
    , "Copy the Secret that is shown in Step 10 because it is only shown once", "Go back to the 'Permissions' menu", <> - Click Add {"->"} API Token Permission -
      -
    • Path: /
    • -
    • API Token: select the API token created in Step 10
    • -
    • Role: PVE Auditor
    • -
    • Propagate: Checked
    • -
    + Click Add {"->"} API Token Permission +
      +
    • Path: /
    • +
    • API Token: select the API token created in Step 10
    • +
    • Role: PVE Auditor
    • +
    • Propagate: Checked
    • +
    , - ], - body: <> - - Sometimes you'll also find the api@pve!homarr format, - within Homarr you'll have to split it up into: - -
      + ], + body: ( + <> + + Sometimes you'll also find the api@pve!homarr format, within Homarr you'll have to split it up + into: + +
      • - Username: api + Username: api
      • - Realm: pve + Realm: pve
      • - Token ID: homarr + Token ID: homarr
      • -
      - -}]} /> \ No newline at end of file +
    + + ), + }, + ]} +/> diff --git a/apps/docs/docs/integrations/q-bittorent/index.mdx b/apps/docs/docs/integrations/q-bittorent/index.mdx index ae85fc0ea..0bf2474ec 100644 --- a/apps/docs/docs/integrations/q-bittorent/index.mdx +++ b/apps/docs/docs/integrations/q-bittorent/index.mdx @@ -1,37 +1,39 @@ --- -title: 'qBittorrent' +title: "qBittorrent" description: "qBittorrent is a free and open-source BitTorrent client." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconDownload } from "@tabler/icons-react"; -import { qBittorentIntegration } from '.'; -import Alert from '@theme/Admonition'; -import { downloadsWidget } from '@site/docs/widgets/downloads'; +import { qBittorentIntegration } from "."; +import Alert from "@theme/Admonition"; +import { downloadsWidget } from "@site/docs/widgets/downloads"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/radarr/index.mdx b/apps/docs/docs/integrations/radarr/index.mdx index 286e1b0b7..09548cab7 100644 --- a/apps/docs/docs/integrations/radarr/index.mdx +++ b/apps/docs/docs/integrations/radarr/index.mdx @@ -1,33 +1,34 @@ --- -title: 'Radarr' +title: "Radarr" description: "Radarr is a movie management tool that automates the process of downloading, sorting, and renaming movies." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconCalendar } from "@tabler/icons-react"; -import { radarrIntegration } from '.'; -import { calendarWidget } from '@site/docs/widgets/calendar'; +import { radarrIntegration } from "."; +import { calendarWidget } from "@site/docs/widgets/calendar"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/readarr/index.mdx b/apps/docs/docs/integrations/readarr/index.mdx index a2c153a91..aec31fe1a 100644 --- a/apps/docs/docs/integrations/readarr/index.mdx +++ b/apps/docs/docs/integrations/readarr/index.mdx @@ -1,33 +1,34 @@ --- -title: 'Readarr' +title: "Readarr" description: "Readarr is a book management tool that automates the process of downloading, sorting, and renaming books." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconCalendar } from "@tabler/icons-react"; -import { readarrIntegration } from '.'; -import { calendarWidget } from '@site/docs/widgets/calendar'; +import { readarrIntegration } from "."; +import { calendarWidget } from "@site/docs/widgets/calendar"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/sabnzbd/index.mdx b/apps/docs/docs/integrations/sabnzbd/index.mdx index 5de72d8c3..8c91c6fef 100644 --- a/apps/docs/docs/integrations/sabnzbd/index.mdx +++ b/apps/docs/docs/integrations/sabnzbd/index.mdx @@ -1,34 +1,35 @@ --- -title: 'SABnzbd' +title: "SABnzbd" description: "SABnzbd is an Open Source Binary Newsreader." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconDownload } from "@tabler/icons-react"; -import { sabnzbdIntegration } from '.'; -import Alert from '@theme/Admonition'; -import { downloadsWidget } from '@site/docs/widgets/downloads'; +import { sabnzbdIntegration } from "."; +import Alert from "@theme/Admonition"; +import { downloadsWidget } from "@site/docs/widgets/downloads"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/seerr/index.mdx b/apps/docs/docs/integrations/seerr/index.mdx index 81b7e0fb1..a1e30798e 100644 --- a/apps/docs/docs/integrations/seerr/index.mdx +++ b/apps/docs/docs/integrations/seerr/index.mdx @@ -1,45 +1,52 @@ --- -title: 'Seerr' +title: "Seerr" description: "Seerr is a self-hosted media request management system that integrates with various media servers." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconZoomQuestion, IconChartBar, IconSearch } from "@tabler/icons-react"; -import { seerrIntegration } from '.'; -import { mediaRequestListWidget } from '@site/docs/widgets/media-request-list'; -import { mediaRequestStatsWidget } from '@site/docs/widgets/media-request-stats'; +import { seerrIntegration } from "."; +import { mediaRequestListWidget } from "@site/docs/widgets/media-request-list"; +import { mediaRequestStatsWidget } from "@site/docs/widgets/media-request-stats"; - - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/slskd/index.mdx b/apps/docs/docs/integrations/slskd/index.mdx index 70674cb04..705ab43c0 100644 --- a/apps/docs/docs/integrations/slskd/index.mdx +++ b/apps/docs/docs/integrations/slskd/index.mdx @@ -1,34 +1,39 @@ --- -title: 'Slskd' +title: "Slskd" description: "A modern client-server application for the Soulseek file sharing network." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { slskdIntegration } from '.'; -import { downloadsWidget } from '@site/docs/widgets/downloads'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { slskdIntegration } from "."; +import { downloadsWidget } from "@site/docs/widgets/downloads"; - - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/sonarr/index.mdx b/apps/docs/docs/integrations/sonarr/index.mdx index 7dc3c7a64..c65d3ce3d 100644 --- a/apps/docs/docs/integrations/sonarr/index.mdx +++ b/apps/docs/docs/integrations/sonarr/index.mdx @@ -1,33 +1,34 @@ --- -title: 'Sonarr' +title: "Sonarr" description: "Sonarr is a TV series management tool that automates the process of downloading, sorting, and renaming episodes." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconCalendar } from "@tabler/icons-react"; -import { sonarrIntegration } from '.'; -import { calendarWidget } from '@site/docs/widgets/calendar'; +import { sonarrIntegration } from "."; +import { calendarWidget } from "@site/docs/widgets/calendar"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/speedtest-tracker/index.mdx b/apps/docs/docs/integrations/speedtest-tracker/index.mdx index 2041dad5c..146a09eca 100644 --- a/apps/docs/docs/integrations/speedtest-tracker/index.mdx +++ b/apps/docs/docs/integrations/speedtest-tracker/index.mdx @@ -1,34 +1,39 @@ --- -title: 'Speedtest Tracker' -description: 'Speedtest Tracker is a self-hosted internet performance tracking application.' +title: "Speedtest Tracker" +description: "Speedtest Tracker is a self-hosted internet performance tracking application." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { speedtestTrackerIntegration } from '.'; -import { speedtestTrackerWidget } from '@site/docs/widgets/speedtest-tracker'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { speedtestTrackerIntegration } from "."; +import { speedtestTrackerWidget } from "@site/docs/widgets/speedtest-tracker"; - - + ### Widgets & Capabilities + ### Adding the integration + ### Secrets - + + diff --git a/apps/docs/docs/integrations/synology/index.mdx b/apps/docs/docs/integrations/synology/index.mdx index 4d836513e..c3f50fc3f 100644 --- a/apps/docs/docs/integrations/synology/index.mdx +++ b/apps/docs/docs/integrations/synology/index.mdx @@ -19,11 +19,7 @@ import Alert from "@theme/Admonition"; ### Widgets & Capabilities ### Supported metrics diff --git a/apps/docs/docs/integrations/tdarr/index.mdx b/apps/docs/docs/integrations/tdarr/index.mdx index 89a0730d2..47956343d 100644 --- a/apps/docs/docs/integrations/tdarr/index.mdx +++ b/apps/docs/docs/integrations/tdarr/index.mdx @@ -1,36 +1,38 @@ --- -title: 'Tdarr' +title: "Tdarr" description: "Tdarr is a distributed media transcoding system that allows you to process and optimize your media files across multiple nodes." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconTransform } from "@tabler/icons-react"; -import { tdarrIntegration } from '.'; -import { mediaTranscodingWidget } from '@site/docs/widgets/media-transcoding'; +import { tdarrIntegration } from "."; +import { mediaTranscodingWidget } from "@site/docs/widgets/media-transcoding"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/technitium-dns/index.mdx b/apps/docs/docs/integrations/technitium-dns/index.mdx index 3ca8bda7c..3bf39d820 100644 --- a/apps/docs/docs/integrations/technitium-dns/index.mdx +++ b/apps/docs/docs/integrations/technitium-dns/index.mdx @@ -1,62 +1,72 @@ --- -title: 'Technitium DNS' +title: "Technitium DNS" description: "Technitium DNS Server is a self-hosted DNS server with ad-blocking and network-wide filtering capabilities." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import Alert from '@theme/Admonition'; -import { technitiumDnsIntegration } from '.'; -import { dnsHoleSummaryWidget } from '@site/docs/widgets/dns-hole-summary'; -import { dnsHoleControlsWidget } from '@site/docs/widgets/dns-hole-controls'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import Alert from "@theme/Admonition"; +import { technitiumDnsIntegration } from "."; +import { dnsHoleSummaryWidget } from "@site/docs/widgets/dns-hole-summary"; +import { dnsHoleControlsWidget } from "@site/docs/widgets/dns-hole-controls"; - + - - Homarr supports Technitium DNS v11 and above. The correct API version is detected automatically - no manual configuration is required. + + Homarr supports Technitium DNS v11 and above. The correct API version is detected automatically - no manual + configuration is required. ### Widgets & Capabilities + ### Adding the integration + ### Secrets - - The **API token** option is recommended. API tokens are non-expiring and do not require storing your admin password in Homarr. - Username and password authentication uses a session token that expires after inactivity, triggering a silent re-login on the next request. + + The **API token** option is recommended. API tokens are non-expiring and do not require storing your admin password in + Homarr. Username and password authentication uses a session token that expires after inactivity, triggering a silent + re-login on the next request. - - The **DNS Hole Controls** widget (enabling, disabling, and timed disabling of blocking) requires the token to have settings-level permissions. - The **DNS Hole Summary** widget (stats only) works with any valid token. - If Homarr cannot read the blocking status due to insufficient permissions, the status indicator will be hidden but statistics will still be shown. + + The **DNS Hole Controls** widget (enabling, disabling, and timed disabling of blocking) requires the token to have + settings-level permissions. The **DNS Hole Summary** widget (stats only) works with any valid token. If Homarr cannot + read the blocking status due to insufficient permissions, the status indicator will be hidden but statistics will + still be shown. - + 'Click on your username in the top-right corner and select "Create API Token".', + 'Give the token a name (e.g. "Homarr") and click "Create Token".', + "Copy the generated token and paste it into the API Key field in Homarr.", + ], + }, + { + credentials: ["username", "password"], + steps: [], + body: "Enter your Technitium DNS admin credentials. Homarr will exchange them for a session token and transparently re-authenticate when the session expires.", + }, + ]} +/> diff --git a/apps/docs/docs/integrations/tracearr/index.mdx b/apps/docs/docs/integrations/tracearr/index.mdx index dc4dde8e0..03954a1cc 100644 --- a/apps/docs/docs/integrations/tracearr/index.mdx +++ b/apps/docs/docs/integrations/tracearr/index.mdx @@ -1,38 +1,37 @@ --- -title: 'Tracearr' +title: "Tracearr" description: "Tracearr is a comprehensive media monitoring solution that tracks streams, user activity, and policy violations in your media server (including Plex, Jellyfin, Emby)." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; -import { tracearrIntegration } from '.'; -import { tracearrWidget } from '@site/docs/widgets/tracearr'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { tracearrIntegration } from "."; +import { tracearrWidget } from "@site/docs/widgets/tracearr"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - - In Tracearr, go to Settings → API and generate or copy your API key. - - ] -}]} /> + In Tracearr, go to Settings → API and generate or copy your API key. + , + ], + }, + ]} +/> diff --git a/apps/docs/docs/integrations/transmission/index.mdx b/apps/docs/docs/integrations/transmission/index.mdx index da0c0209e..c17dbe862 100644 --- a/apps/docs/docs/integrations/transmission/index.mdx +++ b/apps/docs/docs/integrations/transmission/index.mdx @@ -1,34 +1,35 @@ --- -title: 'Transmission' +title: "Transmission" description: "A Fast, Easy and Free Bittorrent Client." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconDownload } from "@tabler/icons-react"; -import { transmissionIntegration } from '.'; -import Alert from '@theme/Admonition'; -import { downloadsWidget } from '@site/docs/widgets/downloads'; +import { transmissionIntegration } from "."; +import Alert from "@theme/Admonition"; +import { downloadsWidget } from "@site/docs/widgets/downloads"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/truenas/index.mdx b/apps/docs/docs/integrations/truenas/index.mdx index 5d29a7019..3ec09bbcf 100644 --- a/apps/docs/docs/integrations/truenas/index.mdx +++ b/apps/docs/docs/integrations/truenas/index.mdx @@ -1,61 +1,67 @@ --- -title: 'TrueNAS' +title: "TrueNAS" description: "Enterprise network-attached storage for your home, office, and cloud." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { truenasIntegration } from '.'; -import { systemResourcesWidget } from '@site/docs/widgets/system-resources'; -import { healthMonitoringWidget } from '@site/docs/widgets/health-monitoring'; -import Alert from '@theme/Admonition'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { truenasIntegration } from "."; +import { systemResourcesWidget } from "@site/docs/widgets/system-resources"; +import { healthMonitoringWidget } from "@site/docs/widgets/health-monitoring"; +import Alert from "@theme/Admonition"; - - + ### Widgets & Capabilities - + + ### Adding the integration + - TrueNAS only serves its API over HTTPS, so enter the https:// URL of your TrueNAS web interface. If it uses a self-signed certificate (the default), add it under Management > Tools > Certificates so Homarr can establish the connection. + TrueNAS only serves its API over HTTPS, so enter the https:// URL of your TrueNAS web interface. If it + uses a self-signed certificate (the default), add it under{" "} + Management > Tools > Certificates so Homarr can establish the + connection. ### Secrets - - API key authentication is the recommended method. It works across current TrueNAS versions and does not depend on user group membership. - , - steps: [ - "In the TrueNAS web interface, click your user avatar in the top-right corner and select \"API Keys\".", - "Click \"Add\", give the key a name such as \"Homarr\", and confirm.", - "Copy the generated key immediately - TrueNAS only shows it once - and paste it as the API Key when creating the integration in Homarr.", - ], + credentials: ["apiKey"], + header: ( + + API key authentication is the recommended method. It works across current TrueNAS versions and does not depend + on user group membership. + + ), + steps: [ + 'In the TrueNAS web interface, click your user avatar in the top-right corner and select "API Keys".', + 'Click "Add", give the key a name such as "Homarr", and confirm.', + "Copy the generated key immediately - TrueNAS only shows it once - and paste it as the API Key when creating the integration in Homarr.", + ], }, { - credentials: ['username', 'password'], - steps: [ - "In the TrueNAS web interface, go to \"Credentials\" > \"Users\" > \"Add\" and create a user with a secure password.", - "Grant the user administrative access so Homarr can read system, pool, and reporting data.", - "Save the user and create the integration in Homarr with these credentials.", - ], - body: - The account must have administrative API access. The auxiliary_administrator group was removed in TrueNAS 25.10; on that version or newer, use API key authentication instead, or assign the user a full-admin role. - , + credentials: ["username", "password"], + steps: [ + 'In the TrueNAS web interface, go to "Credentials" > "Users" > "Add" and create a user with a secure password.', + "Grant the user administrative access so Homarr can read system, pool, and reporting data.", + "Save the user and create the integration in Homarr with these credentials.", + ], + body: ( + + The account must have administrative API access. The auxiliary_administrator group was removed in + TrueNAS 25.10; on that version or newer, use API key authentication instead, or assign the user a full-admin + role. + + ), }, -]} /> + ]} +/> diff --git a/apps/docs/docs/integrations/umami/index.mdx b/apps/docs/docs/integrations/umami/index.mdx index 8aeb3c194..6aa5ddced 100644 --- a/apps/docs/docs/integrations/umami/index.mdx +++ b/apps/docs/docs/integrations/umami/index.mdx @@ -1,53 +1,52 @@ --- -title: 'Umami' -description: 'Privacy-focused, open-source web analytics' +title: "Umami" +description: "Privacy-focused, open-source web analytics" hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { umamiIntegration } from '.'; -import { umamiWidget } from '../../widgets/umami'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { umamiIntegration } from "."; +import { umamiWidget } from "../../widgets/umami"; - + ### Widgets & Capabilities - + + ### Adding the integration + :::tip URL configuration + - **Umami Cloud:** Use `https://api.umami.is/v1` - **Self-hosted:** Use `http://your-umami-host:3000/api` -::: + ::: ### Secrets - + + diff --git a/apps/docs/docs/integrations/unifi-controller/index.mdx b/apps/docs/docs/integrations/unifi-controller/index.mdx index 134ce91b8..f25cecaac 100644 --- a/apps/docs/docs/integrations/unifi-controller/index.mdx +++ b/apps/docs/docs/integrations/unifi-controller/index.mdx @@ -1,40 +1,40 @@ --- -title: 'Unifi Controller' +title: "Unifi Controller" description: "Unifi Controller is a network management platform for Unifi devices." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import {IntegrationSecrets} from '@site/src/components/integrations/secrets'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; import { IconTopologyFull } from "@tabler/icons-react"; -import { unifiControllerIntegration } from '.'; -import { networkControllerSummaryWidget } from '@site/docs/widgets/network-controller-summary'; -import { networkControllerStatusWidget } from '@site/docs/widgets/network-controller-status'; +import { unifiControllerIntegration } from "."; +import { networkControllerSummaryWidget } from "@site/docs/widgets/network-controller-summary"; +import { networkControllerStatusWidget } from "@site/docs/widgets/network-controller-status"; - - + This integration is using the [node-unifi](https://www.npmjs.com/package/node-unifi) library under the hood to connect to the Unifi Controller. Therfore it should support CloudKey Gen1, CloudKey Gen2, UnifiOS-based UDM-Pro controllers as well as self-hosted UniFi controllers. ### Widgets & Capabilities + ### Adding the integration + ### Secrets - \ No newline at end of file + + diff --git a/apps/docs/docs/integrations/unraid/index.mdx b/apps/docs/docs/integrations/unraid/index.mdx index bd1546a78..a629fe844 100644 --- a/apps/docs/docs/integrations/unraid/index.mdx +++ b/apps/docs/docs/integrations/unraid/index.mdx @@ -1,59 +1,71 @@ --- -title: 'Unraid' +title: "Unraid" description: "Versatile operating system that lets you run applications, virtual machines, and storage devices on your server" hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { unraidIntegration } from '.'; -import { systemResourcesWidget } from '@site/docs/widgets/system-resources'; -import { healthMonitoringWidget } from '@site/docs/widgets/health-monitoring'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { unraidIntegration } from "."; +import { systemResourcesWidget } from "@site/docs/widgets/system-resources"; +import { healthMonitoringWidget } from "@site/docs/widgets/health-monitoring"; import imgManagement from "./imgs/unraid-management.png"; import imgCreateApiKey from "./imgs/unraid-create-api-key.png"; import imgCopyApiKey from "./imgs/copy-api-key.png"; import imgSelectApikeyPreset from "./imgs/unraid-select-api-key-preset.png"; - - + ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets -Are you using Unraid pre-7.2? If yes, please first follow the steps here to install the Unraid API., - <> - Open the settings and open the management access
    - Unraid management - , - <> - Click on the "API Keys" tab at the top and click on the "create API key" button. Choose "Create new"
    - Unraid management - , - <> - Enter a suitable name for your API key (e.g. Homarr), select the "Viewer" preset and submit the modal.
    - Unraid management - , - <> - Last, copy the API key after your API key has been created
    - Unraid management - - ], -}]} /> \ No newline at end of file + + + Are you using Unraid pre-7.2? If yes, please first{" "} + + follow the steps here to install the Unraid API + + . + , + <> + Open the settings and open the management access +
    + Unraid management + , + <> + + Click on the "API Keys" tab at the top and click on the "create API key" button. Choose "Create new" + +
    + Unraid management + , + <> + + Enter a suitable name for your API key (e.g. Homarr), select the "Viewer" preset and submit the modal. + +
    + Unraid management + , + <> + Last, copy the API key after your API key has been created +
    + Unraid management + , + ], + }, + ]} +/> diff --git a/apps/docs/docs/integrations/uptime-kuma/index.mdx b/apps/docs/docs/integrations/uptime-kuma/index.mdx index 63e6df82b..14834969f 100644 --- a/apps/docs/docs/integrations/uptime-kuma/index.mdx +++ b/apps/docs/docs/integrations/uptime-kuma/index.mdx @@ -1,43 +1,42 @@ --- -title: 'Uptime Kuma' +title: "Uptime Kuma" description: "Uptime Kuma is a self-hosted monitoring tool that tracks the availability of your services and websites." hide_title: true --- -import { IntegrationHeader } from '@site/src/components/integrations/header'; -import { IntegrationCapabilites } from '@site/src/components/integrations/widgets'; -import { AddingIntegration } from '@site/src/components/integrations/adding'; -import { IntegrationSecrets } from '@site/src/components/integrations/secrets'; -import { uptimeKumaIntegration } from '.'; -import { uptimeKumaWidget } from '@site/docs/widgets/uptime-kuma'; +import { IntegrationHeader } from "@site/src/components/integrations/header"; +import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; +import { AddingIntegration } from "@site/src/components/integrations/adding"; +import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; +import { uptimeKumaIntegration } from "."; +import { uptimeKumaWidget } from "@site/docs/widgets/uptime-kuma"; - - + Uptime Kuma monitors the availability of your services and provides uptime statistics through its status page API. ### Widgets & Capabilities - + + ### Adding the integration + ### Secrets - + ], + }, + ]} +/> :::tip If you don't specify a slug, Homarr will use `default` as the status page slug. diff --git a/apps/docs/docs/management/backup.mdx b/apps/docs/docs/management/backup.mdx index 63959222c..7219d7efc 100644 --- a/apps/docs/docs/management/backup.mdx +++ b/apps/docs/docs/management/backup.mdx @@ -26,10 +26,10 @@ Navigate to `Management` → `Tools` → `Backup`. You must have **admin** permi Click the **Export** button in the export card. You'll be prompted to type `I understand` to confirm. Once confirmed, a ZIP file downloads containing: -| File | Description | -| -------------------- | ------------------------------------------------------------------- | -| `db.sqlite` | Full SQLite database with all entities | -| `metadata.json` | Backup metadata: Homarr version, creation timestamp, encryption key | +| File | Description | +| --------------- | ------------------------------------------------------------------- | +| `db.sqlite` | Full SQLite database with all entities | +| `metadata.json` | Backup metadata: Homarr version, creation timestamp, encryption key | The backup contains the complete database. It includes Custom Widgets and all other Homarr configuration. diff --git a/apps/docs/docs/management/certificates/index.mdx b/apps/docs/docs/management/certificates/index.mdx index cceaa54fd..aa843bfe0 100644 --- a/apps/docs/docs/management/certificates/index.mdx +++ b/apps/docs/docs/management/certificates/index.mdx @@ -7,27 +7,29 @@ tags: --- # Certificates -On this page you can manage your trusted certificates. + +On this page you can manage your trusted certificates. For example if you use a self signed certificate for one of the integrations you want to connect, you can add it here. -Below you can see a screenshot of the certificates page. -The items show the subject, filename and when it expires. +Below you can see a screenshot of the certificates page. +The items show the subject, filename and when it expires. The color of the icon indicates how long it is valid. ![](./img/screenshot.png) -| Color | Meaning | -| --- | --- | -| 🟩 Green | Valid for more than 30 days | +| Color | Meaning | +| --------- | --------------------------- | +| 🟩 Green | Valid for more than 30 days | | 🟨 Yellow | Valid for less than 30 days | -| 🟧 Orange | Valid for less than a week | -| 🟥 Red | Valid for less than a day | - +| 🟧 Orange | Valid for less than a week | +| 🟥 Red | Valid for less than a day | ## Opening the certificates page -Navigate to ``Management`` > ``Tools`` > ``Certificates``. + +Navigate to `Management` > `Tools` > `Certificates`. ## Add a certificate + To add a certificate click on the "Add certificate" button. ![](./img/add-button.png) @@ -62,4 +64,4 @@ Below you can find instructions for some of the integrations. Since version 6 of Pi-hole, the web interface can be accessed through HTTPS. The certificate can be found in the path `/etc/pihole/tls_ca.crt`. To add the certificate, this file needs to be copied and uploaded to Homarr. -You can find more details regarding SSL / TLS for Pi-hole [here](https://docs.pi-hole.net/api/tls/). \ No newline at end of file +You can find more details regarding SSL / TLS for Pi-hole [here](https://docs.pi-hole.net/api/tls/). diff --git a/apps/docs/docs/management/integrations/index.mdx b/apps/docs/docs/management/integrations/index.mdx index 51b3424d3..de819e692 100644 --- a/apps/docs/docs/management/integrations/index.mdx +++ b/apps/docs/docs/management/integrations/index.mdx @@ -6,11 +6,13 @@ tags: --- # Integrations + Integrations are connections to supported third party applications. This page will describe the process of managing integrations but the process may vary depending on your specific integration. Check [the available integrations](/docs/category/integrations) for further information. ## Create an integration + To create an integration, you can choose the supported application from the dropdown at the top right: ![](./img/create-integration-dropdown.png) @@ -20,19 +22,24 @@ Next, you'll need to fill out the required fields to configure the integration: ![](./img/form-create-integration.png) ### Name + Must be at least 1 character long, can be chosen freely. ### Url + This must be the base URL of the application where Homarr should connect to. A few examples for this field include: + - http://sabnzbd.example.com - https://example.com/sabnzbd You must not append any path after the base URL. Some examples for incorrect usage: + - http://sabnzbd.example.com/settings - https://example.com/sabnzbd/settings ### Secrets + An integration may or may not require secrets to function. To process to obtain them is usually [documented in the integration pages](/docs/category/integrations). Secrets are encrypted using a symmetric encryption and stored in the database. @@ -47,6 +54,7 @@ If you already have an application created, you can also link it to the integrat On the edit page you can always change or remove the linked application. ### Testing and saving integration + It is not allowed to create an integration without passing the test. This is to ensure that you minimize the amount of broken applications on your Homarr instance. The test and create button will perform a network request to the application and authenticate if required. @@ -62,6 +70,7 @@ On the edit page of an integration, you can manage which users / groups can ![](./img/integration-permissions.png) ## Troubleshooting connection + The connection to your integrations can fail due to many factors. Most of the time it should show you the reason why it failed. If it doesn't, you can follow these steps to troubleshoot the issue: @@ -70,23 +79,23 @@ If it doesn't, you can follow these steps to troubleshoot the issue: - The secrets must be correct and have the correct permissions. 2. If you use https to connect to the application, check the chapter below about [certificate issues](#certificate-issues). 3. Check whether you followed the Homarr documentation and didn't skip any steps. -This is the most often mistake that create many noisy support requests and following all steps will often resolve the problems. + This is the most often mistake that create many noisy support requests and following all steps will often resolve the problems. 4. Check Homarr's logs for more information. As we have no control over breaking changes in upstream APIs and third party software, -they can break without notice in unexpected ways which can also lead to errors within Homarr. In such case, these occurrences must be reported -and fixed within the source code of Homarr. -5. Check whether the host can reach the destination hostname / IP using ``ping`` and ``curl`` or ``wget`` afterward. -Execute this command on the host machine, not inside containers, to check whether it can connect or not. + they can break without notice in unexpected ways which can also lead to errors within Homarr. In such case, these occurrences must be reported + and fixed within the source code of Homarr. +5. Check whether the host can reach the destination hostname / IP using `ping` and `curl` or `wget` afterward. + Execute this command on the host machine, not inside containers, to check whether it can connect or not. 6. Check whether the container / pod can reach the destination hostname / IP. Execute the same commands in the shell inside the container / pod. 7. Check your reverse proxy / authentication proxy logs for failures / hints 8. Check your security log of tunnels and VPNs 9. Check your router for security events 10. Check your VLAN configuration and firewall rules 11. Check your DNS settings for the host machine and the containers / pods and whether they can resolve the hostnames -12. Check throughput and stability of your network connection using ``iperf3`` +12. Check throughput and stability of your network connection using `iperf3` 13. Check syslog / drivers of your OS for hints 14. Check logs of your destination applications (eg. SABnzbd) 15. Attempt to disable CSRF / tamper protections when absolutely no other workaround available -> this comes with some security implications - be careful! -Re-enable if this didn't fix the issue. + Re-enable if this didn't fix the issue. If none of these troubleshooting steps worked, you can request support from our team in Discord or GitHub. @@ -95,4 +104,4 @@ If none of these troubleshooting steps worked, you can request support from our If you are using a self-signed certificate you'll need to add it to the [trusted certificates](../certificates) in Homarr. Most of the time you should also get a button to add the certificate automatically when you try to connect to the integration. Please check that the certificate is the one you are expecting to prevent Man in the Middle attacks. -For some integrations, you can find a guide on how to retrieve the certificate [here](../certificates/#obtaining-certificates). \ No newline at end of file +For some integrations, you can find a guide on how to retrieve the certificate [here](../certificates/#obtaining-certificates). diff --git a/apps/docs/docs/management/media/index.mdx b/apps/docs/docs/management/media/index.mdx index 090a6559b..e55a05659 100644 --- a/apps/docs/docs/management/media/index.mdx +++ b/apps/docs/docs/management/media/index.mdx @@ -7,7 +7,8 @@ tags: --- # Media + Using the media feature, you can upload images for custom icons to Homarr. Images will be stored in the database. They can be selected in the [icon picker](/docs/advanced/icons). -![](./img/screenshot.png) \ No newline at end of file +![](./img/screenshot.png) diff --git a/apps/docs/docs/management/search-engines/index.mdx b/apps/docs/docs/management/search-engines/index.mdx index ef9fba2a3..07f2f3098 100644 --- a/apps/docs/docs/management/search-engines/index.mdx +++ b/apps/docs/docs/management/search-engines/index.mdx @@ -6,6 +6,7 @@ tags: --- # Search Engines + Using the search engines, terms can be quickly searched simply by opening the search bar at the top or using the keyboard shortcut `CTRL + K`. ![](./img/search-engines.png) @@ -13,31 +14,36 @@ Using the search engines, terms can be quickly searched simply by opening the se You can add any search engine that has a search URL that accepts a search term as a parameter. ## Create search engine + To create a custom search engine, you can click the button at the top of the page. ![](./img/create-search-engine.png) ### Name + The name can be chosen freely. It will be displayed in the search box popover. ### Short + Prefix that is used to choose the search engine in the popover using the keyboard. -It is recommended that this value is kept short (for example ``g`` for Google and ``e`` for Ecosia). +It is recommended that this value is kept short (for example `g` for Google and `e` for Ecosia). ### Configuration In the configuration section you can select between two options. #### Search template -The template must be a valid URL that incldues the ``%s`` placeholder. -Homarr will replace the ``%s`` with the term that the user entered. + +The template must be a valid URL that incldues the `%s` placeholder. +Homarr will replace the `%s` with the term that the user entered. ##### Examples -- Google: ``https://www.google.com/search?q=%s`` -- Ecosia: ``https://www.ecosia.org/search?q=%s`` -- DuckDuckGo: ``https://duckduckgo.com/?q=%s`` -- Bing: ``https://www.bing.com/search?q=%s`` -- YouTube: ``https://www.youtube.com/results?search_query=%s`` + +- Google: `https://www.google.com/search?q=%s` +- Ecosia: `https://www.ecosia.org/search?q=%s` +- DuckDuckGo: `https://duckduckgo.com/?q=%s` +- Bing: `https://www.bing.com/search?q=%s` +- YouTube: `https://www.youtube.com/results?search_query=%s` ## Media request search @@ -45,12 +51,14 @@ Jellyseerr, Overseerr, and Seerr integrations have a dedicated **Spotlight mode* This mode does not require creating a search engine entry - it is available automatically when you have a compatible integration configured. You can access it from: + - The **Modes list** in Spotlight (opened with `CTRL + K`) - The **search button** on the media request list and stats widgets ### Availability indicators Search results display colored status badges showing the media's current state in your integration: + - **Available** - fully available in your media library - **Partial** - some content (e.g. seasons) is available - **Processing** - currently being downloaded or processed diff --git a/apps/docs/docs/management/tasks/index.mdx b/apps/docs/docs/management/tasks/index.mdx index bd9395610..c47eb1a74 100644 --- a/apps/docs/docs/management/tasks/index.mdx +++ b/apps/docs/docs/management/tasks/index.mdx @@ -38,6 +38,3 @@ You can disable a task by clicking the "Power" button, which will change it to a When a task is disabled, it will not run automatically according to its schedule. You can enable it again by clicking the "Power-Off" button, which will change it back to a "Power" button. Running a task manually is still possible when it is disabled. - - - diff --git a/apps/docs/docs/management/users/index.mdx b/apps/docs/docs/management/users/index.mdx index f3f827a73..a7181a1f5 100644 --- a/apps/docs/docs/management/users/index.mdx +++ b/apps/docs/docs/management/users/index.mdx @@ -20,8 +20,10 @@ Homarr supports [single sign on for easier and seamless authentication](/docs/ad ::: ## Manage users + ### Creating new users -To create new users, you must navigate to ``Mangement`` > ``Users`` > ``Manage`` and click on the create button to create a new one: \ + +To create new users, you must navigate to `Mangement` > `Users` > `Manage` and click on the create button to create a new one: \ ![](./img/button-create-user.png) You'll be guided through the process using a wizard: \ @@ -35,25 +37,31 @@ After you completed all steps, you can start over to create another user or choo ![](./img/wizard-complete.png) ## Editing a user -A user can be edited on the ``Mangement`` > ``Users`` > ``Manage`` page when you click on the username. + +A user can be edited on the `Mangement` > `Users` > `Manage` page when you click on the username. Here you'll have access to two tabs: **General** and **Security**. ### General tab + #### Username + This is the unique username that identifies this user. It can be changed to anything but must be at least 3 characters long with a limit of 255 characters. This name will be used for the credential's login. It is also used to auto-generate profile pictures if no picture was uploaded. #### E-Mail + This is the unique email of the user. As of 1.0, it is not used for any notifications and only for organizational purposes. This field is optional. #### Language + This is the currently selected language of the user. Changing the language will change all text & the right to left (RTL) feature in some languages. By default, Homarr will choose English as the default language. Here you can override the language for this specific user. The user may choose a different language by themselves afterward. #### Home board + Optional field for the board that is loaded by default if no board was specified in the URL. Only boards that the user has permission to are being shown. @@ -70,6 +78,7 @@ Choose the first day of the week for the user. This will affect the calendar wid Option to show icons for status check instead of colored dots. #### Delete + This action will permanently delete the user from the database, including any preferences they set. If the user created boards, they wil **not** be deleted. This action is **irreversible** and cannot be undone. All data is permanently lost. @@ -77,6 +86,7 @@ This action is **irreversible** and cannot be undone. All data is permanently lo ### Security tab #### Change password + Here the password for this user can be changed. It must also meet the password requirements of Homarr. The password is stored as an encrypted value with a salt in the database - this means the value cannot be read out from the database afterward. @@ -85,50 +95,63 @@ This functionality can also be useful to lock out a bad actor without tampering For security reasons, you must confirm the password a second time. ## Groups + Using groups, you can manage the permissions of users. Members can be directly assigned to groups. -A user will have the permissions of all groups they are a member of. +A user will have the permissions of all groups they are a member of. Some permissions include other permissions, for example the "Full board access" permission includes all board permissions. By default, a group called "credentials-admin" will be generated where the first user will be placed. However, you can create as many groups as you'd like. ### Creating a group -Click on the button ``New group`` to create a new one. + +Click on the button `New group` to create a new one. Homarr will prompt you for a group name. ### Managing a group + #### General tab + ##### Name + Name for the group that can be chosen freely. ##### Transfer ownership + Every group has an owner. Using this button, the ownership can be transferred to a different user. Group ownership is only organizational. ##### Delete + Deletes the group permanently. This change is irreversible. #### Settings tab + In this tab, you can configure some settings for the group. Those settings will be prioritized by the order of the groups on the groups list page ##### Priorization + The higher a group in the list, the higher the priority. This means that if a user is in multiple groups, the permissions of the group with the highest priority will be used. It will always fallback to the everyone group if no other group permissions are set. ![](./img/groups-list.png) ##### Boards + Configure board settings for a group. User specific settings will override group settings. ###### Home board + The board that is loaded by default if no board was specified in the URL. ###### Mobile board + The board that is loaded by default on mobile devices. #### Members tab + In this tab, you can assign users to the group. With the button at the top right, a new member can be added to the group: ![](./img/add-group-member.png) @@ -138,6 +161,7 @@ Members can be removed from the group using the remove button at the end: ![](./img/remove-group-member.png) #### Permissions tab + In this tab, you manage what permissions the members of this group will have. Currently, the following permissions are available: @@ -163,9 +187,11 @@ When you changed permissions, you must confirm your changes by clicking the bann ![](./img/changing-group-permissions.png) #### Special groups + Currently one special group exists. This group is `everyone`. It automatically adds every user that is known to Homarr to its members. Neither its name nor its members can be changed. ## Invites + Invites are an easy-to-use system to allow users to onboard themselves. It is useful in companies or large-scale homelabs where many users must be onboarded at the same time. You should trust the end user that they enter their data truthfully as the administrator will not confirm the entered data after the user has completed the onboarding. @@ -174,6 +200,7 @@ This feature can only be used when credentials authentication is enabled. An invitation link can be used indefinitely. ### Creating an invitation + Click on the button: ![](./img/create-invitation-button.png) @@ -184,14 +211,15 @@ The default is 4 hours in the future. ![](./img/invitation-expiry-date.png) -Next, click ``Create`` and you'll get a confirmation with an ID, Token and a link that can be copied: +Next, click `Create` and you'll get a confirmation with an ID, Token and a link that can be copied: ![](./img/create-invitation-confirmation.png) Both ID and Token are also in the URL. Ensure that you copy either ID & Token or the URL - it will never be shown again. -Clicking the ``Copy & close`` button will copy the URL to your clipboard. +Clicking the `Copy & close` button will copy the URL to your clipboard. ### Self-onboarding + Clicking the invitation link will bring up a form with fields for the username and password: ![](./img/invitation-self-onboarding.png) @@ -199,6 +227,7 @@ Clicking the invitation link will bring up a form with fields for the username a At the bottom of the page, the user who created the invitation can be seen. ### Deleting an invitation + If an invitation needs to be deleted before or after the expiry, the delete button at the end of the table can be used: ![](./img/deleting-invitation.png) diff --git a/apps/docs/docs/widgets/immich-server-stats/index.mdx b/apps/docs/docs/widgets/immich-server-stats/index.mdx index 64f4d8d02..e2c967365 100644 --- a/apps/docs/docs/widgets/immich-server-stats/index.mdx +++ b/apps/docs/docs/widgets/immich-server-stats/index.mdx @@ -31,6 +31,8 @@ import screen from "./img/screen.png"; ]} /> +In advanced mode, the widget also ranks the largest albums by asset count. To keep the dashboard response lightweight, it shows up to 50 albums. + ### Adding the widget diff --git a/apps/docs/package.json b/apps/docs/package.json index 9da8efba1..ce8dd21ca 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -21,7 +21,7 @@ "verify:search": "node ./scripts/verify-algolia-search.mjs" }, "dependencies": { - "@base-ui/react": "catalog:", + "@base-ui/react": "^1.5.0", "@docusaurus/core": "^3.10.1", "@docusaurus/faster": "^3.10.1", "@docusaurus/plugin-content-docs": "^3.10.1", @@ -37,7 +37,7 @@ "@shadcn/react": "catalog:", "@tabler/icons-react": "catalog:", "@tailwindcss/postcss": "^4.3.2", - "class-variance-authority": "catalog:", + "class-variance-authority": "^0.7.1", "clsx": "catalog:", "cmdk": "catalog:", "date-fns": "catalog:", @@ -58,9 +58,8 @@ "recharts": "3.8.0", "sonner": "catalog:", "swiper": "^14.0.5", - "tailwind-merge": "catalog:", - "tailwindcss": "^4.3.2", - "zod": "catalog:" + "tailwind-merge": "^3.6.0", + "tailwindcss": "^4.3.2" }, "devDependencies": { "@docusaurus/module-type-aliases": "^3.10.1", @@ -71,7 +70,8 @@ "@types/react": "catalog:", "@types/react-dom": "catalog:", "cheerio": "^1.2.0", - "typescript": "catalog:" + "typescript": "catalog:", + "zod": "catalog:" }, "peerDependencies": { "@docusaurus/theme-common": "^3.10.1", diff --git a/apps/docs/scripts/dump-contributors.mjs b/apps/docs/scripts/dump-contributors.mjs index f2cd60fb4..b16057c99 100644 --- a/apps/docs/scripts/dump-contributors.mjs +++ b/apps/docs/scripts/dump-contributors.mjs @@ -1,14 +1,14 @@ -import { z } from 'zod'; -import fs from 'fs/promises'; +import { z } from "zod"; +import fs from "fs/promises"; const sources = { crowdin: [ - { projectId: 534422, tokenName: 'HOMARR_CROWDIN_TOKEN' }, - { projectId: 742587, tokenName: 'HOMARR_LABS_CROWDIN_TOKEN' }, + { projectId: 534422, tokenName: "HOMARR_CROWDIN_TOKEN" }, + { projectId: 742587, tokenName: "HOMARR_LABS_CROWDIN_TOKEN" }, ], github: [ - { repository: 'homarr', slug: 'ajnart' }, - { repository: 'homarr', slug: 'homarr-labs' }, + { repository: "homarr", slug: "ajnart" }, + { repository: "homarr", slug: "homarr-labs" }, ], }; @@ -23,11 +23,11 @@ const env = schema.parse(process.env); const fetchGithubContributors = async (slug, repository) => { const url = `https://api.github.com/repos/${slug}/${repository}/contributors?per_page=999`; const options = { - method: 'GET', + method: "GET", headers: { Authorization: `Bearer ${env.GITHUB_TOKEN}`, - Accept: 'application/vnd.github+json', - 'X-GitHub-Api-Version': '2022-11-28', + Accept: "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", }, }; @@ -39,7 +39,7 @@ const fetchGithubContributors = async (slug, repository) => { login: z.string(), avatar_url: z.string().url(), contributions: z.number(), - }) + }), ); return dataSchema.parse(data); @@ -48,9 +48,9 @@ const fetchGithubContributors = async (slug, repository) => { const fetchCrowdinMembers = async (projectId, tokenName) => { const url = `https://crowdin.com/api/v2/projects/${projectId}/members`; const options = { - method: 'GET', + method: "GET", headers: { - Accept: 'application/json', + Accept: "application/json", Authorization: `Bearer ${env[tokenName]}`, }, }; @@ -65,7 +65,7 @@ const fetchCrowdinMembers = async (projectId, tokenName) => { username: z.string(), avatarUrl: z.string().url(), }), - }) + }), ), }); @@ -88,16 +88,11 @@ const distinctGithubContributors = githubContributors .filter(distinctBy((contributor) => contributor.login)) .sort((a, b) => b.contributions - a.contributions) .map(({ contributions, ...props }) => props) - .filter((contributor) => !contributor.login.includes('[bot]')); -await fs.writeFile('./static/data/contributions.json', JSON.stringify(distinctGithubContributors)); + .filter((contributor) => !contributor.login.includes("[bot]")); +await fs.writeFile("./static/data/contributions.json", JSON.stringify(distinctGithubContributors)); for (const { projectId, tokenName } of sources.crowdin) { crowdinContributors.push(...(await fetchCrowdinMembers(projectId, tokenName))); } -const distinctCrowdinContributors = crowdinContributors.filter( - distinctBy((contributor) => contributor.username) -); -await fs.writeFile( - './static/data/translation-contributions.json', - JSON.stringify(distinctCrowdinContributors) -); +const distinctCrowdinContributors = crowdinContributors.filter(distinctBy((contributor) => contributor.username)); +await fs.writeFile("./static/data/translation-contributions.json", JSON.stringify(distinctCrowdinContributors)); diff --git a/apps/docs/scripts/verify-algolia-search.mjs b/apps/docs/scripts/verify-algolia-search.mjs index 4aa5e30e7..93e83baa8 100644 --- a/apps/docs/scripts/verify-algolia-search.mjs +++ b/apps/docs/scripts/verify-algolia-search.mjs @@ -1,41 +1,32 @@ -const APP_ID = 'N69WSPZTID'; -const API_KEY = 'b2b00f4ed8ca3dc87b5d211c55121416'; -const DOCSEARCH_INDEX = 'Docusaurus'; -const MARKDOWN_INDEX = 'markdown'; +const APP_ID = "N69WSPZTID"; +const API_KEY = "b2b00f4ed8ca3dc87b5d211c55121416"; +const DOCSEARCH_INDEX = "Docusaurus"; +const MARKDOWN_INDEX = "markdown"; const MIN_DOCSEARCH_HITS = 100; const MIN_MARKDOWN_HITS = 10; -const DOCSEARCH_FACETS = [ - 'docusaurus_tag', - 'language', - 'lang', - 'version', - 'type', -]; +const DOCSEARCH_FACETS = ["docusaurus_tag", "language", "lang", "version", "type"]; const SEARCH_CASES = [ - { term: 'docker', minHits: 1 }, - { term: 'coolify', minHits: 1 }, - { term: 'jellyseerr', minHits: 1 }, - { term: 'keyboard shortcuts', minHits: 1 }, - { term: 'version 0.12', minHits: 1 }, + { term: "docker", minHits: 1 }, + { term: "coolify", minHits: 1 }, + { term: "jellyseerr", minHits: 1 }, + { term: "keyboard shortcuts", minHits: 1 }, + { term: "version 0.12", minHits: 1 }, ]; const STALE_URL_PATTERN = /\/docs\/(next|\d+(?:\.\d+)+)\//; async function algoliaQuery(index, body) { - const response = await fetch( - `https://${APP_ID}-dsn.algolia.net/1/indexes/${index}/query`, - { - method: 'POST', - headers: { - 'X-Algolia-Application-Id': APP_ID, - 'X-Algolia-API-Key': API_KEY, - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body), + const response = await fetch(`https://${APP_ID}-dsn.algolia.net/1/indexes/${index}/query`, { + method: "POST", + headers: { + "X-Algolia-Application-Id": APP_ID, + "X-Algolia-API-Key": API_KEY, + "Content-Type": "application/json", }, - ); + body: JSON.stringify(body), + }); if (!response.ok) { throw new Error(`Algolia query on "${index}" failed: HTTP ${response.status}`); @@ -45,7 +36,7 @@ async function algoliaQuery(index, body) { } function reportLine(ok, message) { - const prefix = ok ? 'OK' : 'FAIL'; + const prefix = ok ? "OK" : "FAIL"; console.log(`${prefix}: ${message}`); return ok; } @@ -54,14 +45,14 @@ async function resolveDocsearchIndex() { const candidates = [DOCSEARCH_INDEX, `${DOCSEARCH_INDEX}.tmp`]; for (const index of candidates) { - const result = await algoliaQuery(index, { query: '', hitsPerPage: 0 }); + const result = await algoliaQuery(index, { query: "", hitsPerPage: 0 }); const hitCount = result.nbHits ?? 0; if (hitCount >= MIN_DOCSEARCH_HITS) { return { index, hitCount }; } } - const fallback = await algoliaQuery(DOCSEARCH_INDEX, { query: '', hitsPerPage: 0 }); + const fallback = await algoliaQuery(DOCSEARCH_INDEX, { query: "", hitsPerPage: 0 }); return { index: DOCSEARCH_INDEX, hitCount: fallback.nbHits ?? 0 }; } @@ -69,14 +60,14 @@ async function resolveMarkdownIndex() { const candidates = [MARKDOWN_INDEX, `${MARKDOWN_INDEX}.tmp`]; for (const index of candidates) { - const result = await algoliaQuery(index, { query: '', hitsPerPage: 0 }); + const result = await algoliaQuery(index, { query: "", hitsPerPage: 0 }); const hitCount = result.nbHits ?? 0; if (hitCount >= MIN_MARKDOWN_HITS) { return { index, hitCount }; } } - const fallback = await algoliaQuery(MARKDOWN_INDEX, { query: '', hitsPerPage: 0 }); + const fallback = await algoliaQuery(MARKDOWN_INDEX, { query: "", hitsPerPage: 0 }); return { index: MARKDOWN_INDEX, hitCount: fallback.nbHits ?? 0 }; } @@ -87,13 +78,13 @@ async function verifyDocsearchIndex(index, hitCount) { ); const sample = await algoliaQuery(index, { - query: 'docker', + query: "docker", hitsPerPage: 1, attributesToRetrieve: DOCSEARCH_FACETS, }); const record = sample.hits?.[0] ?? {}; - const recordFields = ['docusaurus_tag', 'language', 'lang', 'version', 'type']; + const recordFields = ["docusaurus_tag", "language", "lang", "version", "type"]; for (const field of recordFields) { const present = record[field] !== undefined && record[field] !== null; ok = reportLine(present, `records include "${field}"`) && ok; @@ -103,7 +94,7 @@ async function verifyDocsearchIndex(index, hitCount) { const result = await algoliaQuery(index, { query: searchCase.term, hitsPerPage: 5, - attributesToRetrieve: ['url'], + attributesToRetrieve: ["url"], }); const caseHits = result.nbHits ?? 0; @@ -113,9 +104,7 @@ async function verifyDocsearchIndex(index, hitCount) { `"${searchCase.term}" returns ${caseHits} hits (need >= ${searchCase.minHits})`, ) && ok; - const staleUrls = (result.hits ?? []) - .map((hit) => hit.url) - .filter((url) => STALE_URL_PATTERN.test(url)); + const staleUrls = (result.hits ?? []).map((hit) => hit.url).filter((url) => STALE_URL_PATTERN.test(url)); ok = reportLine( @@ -134,51 +123,39 @@ async function verifyMarkdownIndex(index, hitCount) { ); const coolify = await algoliaQuery(index, { - query: 'coolify', + query: "coolify", hitsPerPage: 3, - attributesToRetrieve: ['url', 'title', 'heading', 'text'], + attributesToRetrieve: ["url", "title", "heading", "text"], }); ok = - reportLine( - (coolify.nbHits ?? 0) >= 1, - `markdown index "${index}" returns coolify (${coolify.nbHits ?? 0} hits)`, - ) && ok; + reportLine((coolify.nbHits ?? 0) >= 1, `markdown index "${index}" returns coolify (${coolify.nbHits ?? 0} hits)`) && + ok; const sample = coolify.hits?.[0]; - ok = - reportLine( - Boolean(sample?.text?.length), - `markdown records include chunked text content`, - ) && ok; + ok = reportLine(Boolean(sample?.text?.length), `markdown records include chunked text content`) && ok; return ok; } async function main() { - console.log('Verifying Algolia DocSearch + markdown indices...\n'); + console.log("Verifying Algolia DocSearch + markdown indices...\n"); const docsearch = await resolveDocsearchIndex(); console.log(`Using DocSearch index: ${docsearch.index}\n`); - const docsearchOk = await verifyDocsearchIndex( - docsearch.index, - docsearch.hitCount, - ); + const docsearchOk = await verifyDocsearchIndex(docsearch.index, docsearch.hitCount); - console.log(''); + console.log(""); const markdown = await resolveMarkdownIndex(); console.log(`Using markdown index: ${markdown.index}\n`); - const markdownOk = await verifyMarkdownIndex( - markdown.index, - markdown.hitCount, - ); + const markdownOk = await verifyMarkdownIndex(markdown.index, markdown.hitCount); const allOk = docsearchOk && markdownOk; - console.log(''); + console.log(""); console.log( allOk - ? 'All checks passed.' - : 'Some checks failed — ensure the crawler config in docsearch.config.js is applied and a full recrawl has finished.', + ? "All checks passed." + : "Some checks failed — ensure the crawler config in docsearch.config.js is applied and a full recrawl has finished.", ); process.exit(allOk ? 0 : 1); } diff --git a/apps/docs/src/components/pages/home/integrations/available-integrations.module.css b/apps/docs/src/components/pages/home/integrations/available-integrations.module.css index a9c057d1c..d65f59e95 100644 --- a/apps/docs/src/components/pages/home/integrations/available-integrations.module.css +++ b/apps/docs/src/components/pages/home/integrations/available-integrations.module.css @@ -1,20 +1,20 @@ @keyframes scrolling { - 0% { - transform: translateY(0); - } - 100% { - transform: translateY(-50.8%); - } + 0% { + transform: translateY(0); + } + 100% { + transform: translateY(-50.8%); + } } .scrollAnimationContainer { - animation: scrolling; - animation-timing-function: linear; - animation-iteration-count: infinite; + animation: scrolling; + animation-timing-function: linear; + animation-iteration-count: infinite; } @media (prefers-reduced-motion: reduce) { - .scrollAnimationContainer { - animation: none !important; - } -} \ No newline at end of file + .scrollAnimationContainer { + animation: none !important; + } +} diff --git a/apps/docs/src/components/pages/home/review-list/styles.module.css b/apps/docs/src/components/pages/home/review-list/styles.module.css index 5cff5a7d2..53f4abaaa 100644 --- a/apps/docs/src/components/pages/home/review-list/styles.module.css +++ b/apps/docs/src/components/pages/home/review-list/styles.module.css @@ -4,8 +4,6 @@ margin-bottom: 50px; } - - .communityFeedbackPlaceholderImage { display: block; margin: 0 auto; @@ -14,5 +12,3 @@ .communityFeedbackPlaceholderText { text-align: center; } - - diff --git a/apps/docs/src/pages/index.module.css b/apps/docs/src/pages/index.module.css index 513376a12..36af84e40 100644 --- a/apps/docs/src/pages/index.module.css +++ b/apps/docs/src/pages/index.module.css @@ -27,7 +27,6 @@ section { max-width: min(100%, 500px); } - .heroBanner { padding: clamp(3rem, 6vw, 6rem) clamp(1.25rem, 4vw, 4rem); position: relative; diff --git a/apps/docs/static/data/contributions.json b/apps/docs/static/data/contributions.json index fbc3a2a80..18dd6bc05 100644 --- a/apps/docs/static/data/contributions.json +++ b/apps/docs/static/data/contributions.json @@ -1 +1,127 @@ -[{"login":"ajnart","avatar_url":"https://avatars.githubusercontent.com/u/49837342?v=4"},{"login":"manuel-rw","avatar_url":"https://avatars.githubusercontent.com/u/30572287?v=4"},{"login":"Meierschlumpf","avatar_url":"https://avatars.githubusercontent.com/u/63781622?v=4"},{"login":"SeDemal","avatar_url":"https://avatars.githubusercontent.com/u/26098587?v=4"},{"login":"lammersbjorn","avatar_url":"https://avatars.githubusercontent.com/u/71191962?v=4"},{"login":"LarveyOfficial","avatar_url":"https://avatars.githubusercontent.com/u/39219859?v=4"},{"login":"c00ldude1oo","avatar_url":"https://avatars.githubusercontent.com/u/15677803?v=4"},{"login":"InterN0te","avatar_url":"https://avatars.githubusercontent.com/u/10882916?v=4"},{"login":"Aandree5","avatar_url":"https://avatars.githubusercontent.com/u/32734153?v=4"},{"login":"Aimsucks","avatar_url":"https://avatars.githubusercontent.com/u/1828486?v=4"},{"login":"JannesV","avatar_url":"https://avatars.githubusercontent.com/u/5984244?v=4"},{"login":"MauriceNino","avatar_url":"https://avatars.githubusercontent.com/u/18658092?v=4"},{"login":"hillaliy","avatar_url":"https://avatars.githubusercontent.com/u/950010?v=4"},{"login":"Skeeww","avatar_url":"https://avatars.githubusercontent.com/u/9639992?v=4"},{"login":"jackwellerreal","avatar_url":"https://avatars.githubusercontent.com/u/97435840?v=4"},{"login":"RichyHBM","avatar_url":"https://avatars.githubusercontent.com/u/5472275?v=4"},{"login":"Bonfire","avatar_url":"https://avatars.githubusercontent.com/u/5704760?v=4"},{"login":"wieli99","avatar_url":"https://avatars.githubusercontent.com/u/46794825?v=4"},{"login":"ishaanparlikar","avatar_url":"https://avatars.githubusercontent.com/u/43013132?v=4"},{"login":"Zareix","avatar_url":"https://avatars.githubusercontent.com/u/29818713?v=4"},{"login":"tuggan","avatar_url":"https://avatars.githubusercontent.com/u/4325608?v=4"},{"login":"mvanhorn","avatar_url":"https://avatars.githubusercontent.com/u/455140?v=4"},{"login":"SergioChan","avatar_url":"https://avatars.githubusercontent.com/u/10103766?v=4"},{"login":"toineenzo","avatar_url":"https://avatars.githubusercontent.com/u/4921397?v=4"},{"login":"oben01","avatar_url":"https://avatars.githubusercontent.com/u/22369027?v=4"},{"login":"rezstje","avatar_url":"https://avatars.githubusercontent.com/u/45420315?v=4"},{"login":"Spillebulle","avatar_url":"https://avatars.githubusercontent.com/u/46653946?v=4"},{"login":"marektancak0106","avatar_url":"https://avatars.githubusercontent.com/u/25422667?v=4"},{"login":"spkesDE","avatar_url":"https://avatars.githubusercontent.com/u/1682314?v=4"},{"login":"j3lte","avatar_url":"https://avatars.githubusercontent.com/u/2557568?v=4"},{"login":"dslatt","avatar_url":"https://avatars.githubusercontent.com/u/5211001?v=4"},{"login":"Malong11-007","avatar_url":"https://avatars.githubusercontent.com/u/40298510?v=4"},{"login":"castielwaverly","avatar_url":"https://avatars.githubusercontent.com/u/137005689?v=4"},{"login":"xoxyuxu","avatar_url":"https://avatars.githubusercontent.com/u/3543416?v=4"},{"login":"StrandedTurtle","avatar_url":"https://avatars.githubusercontent.com/u/132835255?v=4"},{"login":"MaienM","avatar_url":"https://avatars.githubusercontent.com/u/583129?v=4"},{"login":"kylegrieder","avatar_url":"https://avatars.githubusercontent.com/u/25424229?v=4"},{"login":"HeapReaper","avatar_url":"https://avatars.githubusercontent.com/u/31496522?v=4"},{"login":"Copilot","avatar_url":"https://avatars.githubusercontent.com/in/1143301?v=4"},{"login":"Gilmoursa","avatar_url":"https://avatars.githubusercontent.com/u/10321421?v=4"},{"login":"StefanB7","avatar_url":"https://avatars.githubusercontent.com/u/22056509?v=4"},{"login":"souravghosh01","avatar_url":"https://avatars.githubusercontent.com/u/37548139?v=4"},{"login":"SR3u","avatar_url":"https://avatars.githubusercontent.com/u/2380522?v=4"},{"login":"Rikpat","avatar_url":"https://avatars.githubusercontent.com/u/33869814?v=4"},{"login":"NormanJS","avatar_url":"https://avatars.githubusercontent.com/u/83409549?v=4"},{"login":"No-Maines-Land","avatar_url":"https://avatars.githubusercontent.com/u/20687725?v=4"},{"login":"stark1tty","avatar_url":"https://avatars.githubusercontent.com/u/69326376?v=4"},{"login":"Momcilo42","avatar_url":"https://avatars.githubusercontent.com/u/10118137?v=4"},{"login":"marius-arch","avatar_url":"https://avatars.githubusercontent.com/u/72494359?v=4"},{"login":"Lumilias","avatar_url":"https://avatars.githubusercontent.com/u/10852161?v=4"},{"login":"Havock94","avatar_url":"https://avatars.githubusercontent.com/u/7635248?v=4"},{"login":"Lollyde","avatar_url":"https://avatars.githubusercontent.com/u/11347524?v=4"},{"login":"krishnamuppaneni","avatar_url":"https://avatars.githubusercontent.com/u/4703366?v=4"},{"login":"devtobi","avatar_url":"https://avatars.githubusercontent.com/u/28538704?v=4"},{"login":"TyxTang","avatar_url":"https://avatars.githubusercontent.com/u/90897955?v=4"},{"login":"alotlikebeans","avatar_url":"https://avatars.githubusercontent.com/u/19630511?v=4"},{"login":"WillyJL","avatar_url":"https://avatars.githubusercontent.com/u/49810075?v=4"},{"login":"anonysoul","avatar_url":"https://avatars.githubusercontent.com/u/105715150?v=4"},{"login":"cospeedster","avatar_url":"https://avatars.githubusercontent.com/u/52749645?v=4"},{"login":"diederbert","avatar_url":"https://avatars.githubusercontent.com/u/162878798?v=4"},{"login":"digdilem","avatar_url":"https://avatars.githubusercontent.com/u/4052275?v=4"},{"login":"dinghino","avatar_url":"https://avatars.githubusercontent.com/u/14729459?v=4"},{"login":"gfomichev","avatar_url":"https://avatars.githubusercontent.com/u/1596146?v=4"},{"login":"gnattu","avatar_url":"https://avatars.githubusercontent.com/u/12995396?v=4"},{"login":"tuxpizza","avatar_url":"https://avatars.githubusercontent.com/u/84710786?v=4"},{"login":"xmarkurion","avatar_url":"https://avatars.githubusercontent.com/u/46654687?v=4"},{"login":"huanga","avatar_url":"https://avatars.githubusercontent.com/u/732970?v=4"},{"login":"taos15","avatar_url":"https://avatars.githubusercontent.com/u/122130728?v=4"},{"login":"arghyadipchak","avatar_url":"https://avatars.githubusercontent.com/u/32430374?v=4"},{"login":"AuthorShin","avatar_url":"https://avatars.githubusercontent.com/u/4959043?v=4"},{"login":"benniblot","avatar_url":"https://avatars.githubusercontent.com/u/47495914?v=4"},{"login":"bebsworthy","avatar_url":"https://avatars.githubusercontent.com/u/5266759?v=4"},{"login":"catrielmuller","avatar_url":"https://avatars.githubusercontent.com/u/2272323?v=4"},{"login":"Vysp3r","avatar_url":"https://avatars.githubusercontent.com/u/62019735?v=4"},{"login":"DR-Blogs","avatar_url":"https://avatars.githubusercontent.com/u/96393186?v=4"},{"login":"singular0","avatar_url":"https://avatars.githubusercontent.com/u/1925883?v=4"},{"login":"diogovalentte","avatar_url":"https://avatars.githubusercontent.com/u/49578155?v=4"},{"login":"codezninja","avatar_url":"https://avatars.githubusercontent.com/u/4400773?v=4"},{"login":"fabricionaweb","avatar_url":"https://avatars.githubusercontent.com/u/15933?v=4"},{"login":"nyok1912","avatar_url":"https://avatars.githubusercontent.com/u/32163949?v=4"},{"login":"bo3bdo","avatar_url":"https://avatars.githubusercontent.com/u/5271380?v=4"},{"login":"hskrtich","avatar_url":"https://avatars.githubusercontent.com/u/1214484?v=4"},{"login":"ishults","avatar_url":"https://avatars.githubusercontent.com/u/7275442?v=4"},{"login":"jelliuk","avatar_url":"https://avatars.githubusercontent.com/u/4790959?v=4"},{"login":"Moohan","avatar_url":"https://avatars.githubusercontent.com/u/5982260?v=4"},{"login":"tesar-tech","avatar_url":"https://avatars.githubusercontent.com/u/33880579?v=4"},{"login":"jbruell","avatar_url":"https://avatars.githubusercontent.com/u/31685172?v=4"},{"login":"JasonLeeB06","avatar_url":"https://avatars.githubusercontent.com/u/82266978?v=4"},{"login":"jeffersonraimon","avatar_url":"https://avatars.githubusercontent.com/u/80064475?v=4"},{"login":"jo-chemla","avatar_url":"https://avatars.githubusercontent.com/u/16822841?v=4"},{"login":"joser93","avatar_url":"https://avatars.githubusercontent.com/u/6912089?v=4"},{"login":"justijndepover","avatar_url":"https://avatars.githubusercontent.com/u/9008623?v=4"},{"login":"leandroscardua","avatar_url":"https://avatars.githubusercontent.com/u/24698541?v=4"},{"login":"mairas","avatar_url":"https://avatars.githubusercontent.com/u/407010?v=4"},{"login":"itzTheMeow","avatar_url":"https://avatars.githubusercontent.com/u/50887230?v=4"},{"login":"NicolasNewman","avatar_url":"https://avatars.githubusercontent.com/u/16135852?v=4"},{"login":"NikeLaosClericus","avatar_url":"https://avatars.githubusercontent.com/u/39810627?v=4"},{"login":"noahcroghan","avatar_url":"https://avatars.githubusercontent.com/u/27422774?v=4"},{"login":"ohmzi","avatar_url":"https://avatars.githubusercontent.com/u/6551272?v=4"},{"login":"Rhiz3K","avatar_url":"https://avatars.githubusercontent.com/u/33246262?v=4"},{"login":"saschabuehrle","avatar_url":"https://avatars.githubusercontent.com/u/47737812?v=4"},{"login":"CrazyWolf13","avatar_url":"https://avatars.githubusercontent.com/u/96661824?v=4"},{"login":"VIVAAN-DHAWAN","avatar_url":"https://avatars.githubusercontent.com/u/150339722?v=4"},{"login":"generalmat82","avatar_url":"https://avatars.githubusercontent.com/u/110256073?v=4"},{"login":"lthomsen","avatar_url":"https://avatars.githubusercontent.com/u/28560325?v=4"},{"login":"pitschi","avatar_url":"https://avatars.githubusercontent.com/u/6841565?v=4"},{"login":"sharpsalat","avatar_url":"https://avatars.githubusercontent.com/u/15666932?v=4"},{"login":"tech62","avatar_url":"https://avatars.githubusercontent.com/u/16237642?v=4"},{"login":"AartSchinkel","avatar_url":"https://avatars.githubusercontent.com/u/189675191?v=4"},{"login":"afonsojramos","avatar_url":"https://avatars.githubusercontent.com/u/19473034?v=4"},{"login":"m0s4ik","avatar_url":"https://avatars.githubusercontent.com/u/26578395?v=4"},{"login":"ashtonbatty","avatar_url":"https://avatars.githubusercontent.com/u/230635?v=4"},{"login":"Oupsman","avatar_url":"https://avatars.githubusercontent.com/u/11260343?v=4"},{"login":"cethien","avatar_url":"https://avatars.githubusercontent.com/u/60463918?v=4"},{"login":"DZ945brH","avatar_url":"https://avatars.githubusercontent.com/u/42635243?v=4"},{"login":"dgshue","avatar_url":"https://avatars.githubusercontent.com/u/12952156?v=4"},{"login":"d-lindahl","avatar_url":"https://avatars.githubusercontent.com/u/690410?v=4"},{"login":"KartulUdus","avatar_url":"https://avatars.githubusercontent.com/u/23346150?v=4"},{"login":"ieugen","avatar_url":"https://avatars.githubusercontent.com/u/1050920?v=4"},{"login":"faugusto-oliveira","avatar_url":"https://avatars.githubusercontent.com/u/37384074?v=4"},{"login":"frankvHoof93","avatar_url":"https://avatars.githubusercontent.com/u/7346516?v=4"},{"login":"febrile42","avatar_url":"https://avatars.githubusercontent.com/u/14597122?v=4"},{"login":"Kaotic3","avatar_url":"https://avatars.githubusercontent.com/u/80522225?v=4"},{"login":"KelianB","avatar_url":"https://avatars.githubusercontent.com/u/11216155?v=4"},{"login":"hotrungnhan","avatar_url":"https://avatars.githubusercontent.com/u/40029631?v=4"}] \ No newline at end of file +[ + { "login": "ajnart", "avatar_url": "https://avatars.githubusercontent.com/u/49837342?v=4" }, + { "login": "manuel-rw", "avatar_url": "https://avatars.githubusercontent.com/u/30572287?v=4" }, + { "login": "Meierschlumpf", "avatar_url": "https://avatars.githubusercontent.com/u/63781622?v=4" }, + { "login": "SeDemal", "avatar_url": "https://avatars.githubusercontent.com/u/26098587?v=4" }, + { "login": "lammersbjorn", "avatar_url": "https://avatars.githubusercontent.com/u/71191962?v=4" }, + { "login": "LarveyOfficial", "avatar_url": "https://avatars.githubusercontent.com/u/39219859?v=4" }, + { "login": "c00ldude1oo", "avatar_url": "https://avatars.githubusercontent.com/u/15677803?v=4" }, + { "login": "InterN0te", "avatar_url": "https://avatars.githubusercontent.com/u/10882916?v=4" }, + { "login": "Aandree5", "avatar_url": "https://avatars.githubusercontent.com/u/32734153?v=4" }, + { "login": "Aimsucks", "avatar_url": "https://avatars.githubusercontent.com/u/1828486?v=4" }, + { "login": "JannesV", "avatar_url": "https://avatars.githubusercontent.com/u/5984244?v=4" }, + { "login": "MauriceNino", "avatar_url": "https://avatars.githubusercontent.com/u/18658092?v=4" }, + { "login": "hillaliy", "avatar_url": "https://avatars.githubusercontent.com/u/950010?v=4" }, + { "login": "Skeeww", "avatar_url": "https://avatars.githubusercontent.com/u/9639992?v=4" }, + { "login": "jackwellerreal", "avatar_url": "https://avatars.githubusercontent.com/u/97435840?v=4" }, + { "login": "RichyHBM", "avatar_url": "https://avatars.githubusercontent.com/u/5472275?v=4" }, + { "login": "Bonfire", "avatar_url": "https://avatars.githubusercontent.com/u/5704760?v=4" }, + { "login": "wieli99", "avatar_url": "https://avatars.githubusercontent.com/u/46794825?v=4" }, + { "login": "ishaanparlikar", "avatar_url": "https://avatars.githubusercontent.com/u/43013132?v=4" }, + { "login": "Zareix", "avatar_url": "https://avatars.githubusercontent.com/u/29818713?v=4" }, + { "login": "tuggan", "avatar_url": "https://avatars.githubusercontent.com/u/4325608?v=4" }, + { "login": "mvanhorn", "avatar_url": "https://avatars.githubusercontent.com/u/455140?v=4" }, + { "login": "SergioChan", "avatar_url": "https://avatars.githubusercontent.com/u/10103766?v=4" }, + { "login": "toineenzo", "avatar_url": "https://avatars.githubusercontent.com/u/4921397?v=4" }, + { "login": "oben01", "avatar_url": "https://avatars.githubusercontent.com/u/22369027?v=4" }, + { "login": "rezstje", "avatar_url": "https://avatars.githubusercontent.com/u/45420315?v=4" }, + { "login": "Spillebulle", "avatar_url": "https://avatars.githubusercontent.com/u/46653946?v=4" }, + { "login": "marektancak0106", "avatar_url": "https://avatars.githubusercontent.com/u/25422667?v=4" }, + { "login": "spkesDE", "avatar_url": "https://avatars.githubusercontent.com/u/1682314?v=4" }, + { "login": "j3lte", "avatar_url": "https://avatars.githubusercontent.com/u/2557568?v=4" }, + { "login": "dslatt", "avatar_url": "https://avatars.githubusercontent.com/u/5211001?v=4" }, + { "login": "Malong11-007", "avatar_url": "https://avatars.githubusercontent.com/u/40298510?v=4" }, + { "login": "castielwaverly", "avatar_url": "https://avatars.githubusercontent.com/u/137005689?v=4" }, + { "login": "xoxyuxu", "avatar_url": "https://avatars.githubusercontent.com/u/3543416?v=4" }, + { "login": "StrandedTurtle", "avatar_url": "https://avatars.githubusercontent.com/u/132835255?v=4" }, + { "login": "MaienM", "avatar_url": "https://avatars.githubusercontent.com/u/583129?v=4" }, + { "login": "kylegrieder", "avatar_url": "https://avatars.githubusercontent.com/u/25424229?v=4" }, + { "login": "HeapReaper", "avatar_url": "https://avatars.githubusercontent.com/u/31496522?v=4" }, + { "login": "Copilot", "avatar_url": "https://avatars.githubusercontent.com/in/1143301?v=4" }, + { "login": "Gilmoursa", "avatar_url": "https://avatars.githubusercontent.com/u/10321421?v=4" }, + { "login": "StefanB7", "avatar_url": "https://avatars.githubusercontent.com/u/22056509?v=4" }, + { "login": "souravghosh01", "avatar_url": "https://avatars.githubusercontent.com/u/37548139?v=4" }, + { "login": "SR3u", "avatar_url": "https://avatars.githubusercontent.com/u/2380522?v=4" }, + { "login": "Rikpat", "avatar_url": "https://avatars.githubusercontent.com/u/33869814?v=4" }, + { "login": "NormanJS", "avatar_url": "https://avatars.githubusercontent.com/u/83409549?v=4" }, + { "login": "No-Maines-Land", "avatar_url": "https://avatars.githubusercontent.com/u/20687725?v=4" }, + { "login": "stark1tty", "avatar_url": "https://avatars.githubusercontent.com/u/69326376?v=4" }, + { "login": "Momcilo42", "avatar_url": "https://avatars.githubusercontent.com/u/10118137?v=4" }, + { "login": "marius-arch", "avatar_url": "https://avatars.githubusercontent.com/u/72494359?v=4" }, + { "login": "Lumilias", "avatar_url": "https://avatars.githubusercontent.com/u/10852161?v=4" }, + { "login": "Havock94", "avatar_url": "https://avatars.githubusercontent.com/u/7635248?v=4" }, + { "login": "Lollyde", "avatar_url": "https://avatars.githubusercontent.com/u/11347524?v=4" }, + { "login": "krishnamuppaneni", "avatar_url": "https://avatars.githubusercontent.com/u/4703366?v=4" }, + { "login": "devtobi", "avatar_url": "https://avatars.githubusercontent.com/u/28538704?v=4" }, + { "login": "TyxTang", "avatar_url": "https://avatars.githubusercontent.com/u/90897955?v=4" }, + { "login": "alotlikebeans", "avatar_url": "https://avatars.githubusercontent.com/u/19630511?v=4" }, + { "login": "WillyJL", "avatar_url": "https://avatars.githubusercontent.com/u/49810075?v=4" }, + { "login": "anonysoul", "avatar_url": "https://avatars.githubusercontent.com/u/105715150?v=4" }, + { "login": "cospeedster", "avatar_url": "https://avatars.githubusercontent.com/u/52749645?v=4" }, + { "login": "diederbert", "avatar_url": "https://avatars.githubusercontent.com/u/162878798?v=4" }, + { "login": "digdilem", "avatar_url": "https://avatars.githubusercontent.com/u/4052275?v=4" }, + { "login": "dinghino", "avatar_url": "https://avatars.githubusercontent.com/u/14729459?v=4" }, + { "login": "gfomichev", "avatar_url": "https://avatars.githubusercontent.com/u/1596146?v=4" }, + { "login": "gnattu", "avatar_url": "https://avatars.githubusercontent.com/u/12995396?v=4" }, + { "login": "tuxpizza", "avatar_url": "https://avatars.githubusercontent.com/u/84710786?v=4" }, + { "login": "xmarkurion", "avatar_url": "https://avatars.githubusercontent.com/u/46654687?v=4" }, + { "login": "huanga", "avatar_url": "https://avatars.githubusercontent.com/u/732970?v=4" }, + { "login": "taos15", "avatar_url": "https://avatars.githubusercontent.com/u/122130728?v=4" }, + { "login": "arghyadipchak", "avatar_url": "https://avatars.githubusercontent.com/u/32430374?v=4" }, + { "login": "AuthorShin", "avatar_url": "https://avatars.githubusercontent.com/u/4959043?v=4" }, + { "login": "benniblot", "avatar_url": "https://avatars.githubusercontent.com/u/47495914?v=4" }, + { "login": "bebsworthy", "avatar_url": "https://avatars.githubusercontent.com/u/5266759?v=4" }, + { "login": "catrielmuller", "avatar_url": "https://avatars.githubusercontent.com/u/2272323?v=4" }, + { "login": "Vysp3r", "avatar_url": "https://avatars.githubusercontent.com/u/62019735?v=4" }, + { "login": "DR-Blogs", "avatar_url": "https://avatars.githubusercontent.com/u/96393186?v=4" }, + { "login": "singular0", "avatar_url": "https://avatars.githubusercontent.com/u/1925883?v=4" }, + { "login": "diogovalentte", "avatar_url": "https://avatars.githubusercontent.com/u/49578155?v=4" }, + { "login": "codezninja", "avatar_url": "https://avatars.githubusercontent.com/u/4400773?v=4" }, + { "login": "fabricionaweb", "avatar_url": "https://avatars.githubusercontent.com/u/15933?v=4" }, + { "login": "nyok1912", "avatar_url": "https://avatars.githubusercontent.com/u/32163949?v=4" }, + { "login": "bo3bdo", "avatar_url": "https://avatars.githubusercontent.com/u/5271380?v=4" }, + { "login": "hskrtich", "avatar_url": "https://avatars.githubusercontent.com/u/1214484?v=4" }, + { "login": "ishults", "avatar_url": "https://avatars.githubusercontent.com/u/7275442?v=4" }, + { "login": "jelliuk", "avatar_url": "https://avatars.githubusercontent.com/u/4790959?v=4" }, + { "login": "Moohan", "avatar_url": "https://avatars.githubusercontent.com/u/5982260?v=4" }, + { "login": "tesar-tech", "avatar_url": "https://avatars.githubusercontent.com/u/33880579?v=4" }, + { "login": "jbruell", "avatar_url": "https://avatars.githubusercontent.com/u/31685172?v=4" }, + { "login": "JasonLeeB06", "avatar_url": "https://avatars.githubusercontent.com/u/82266978?v=4" }, + { "login": "jeffersonraimon", "avatar_url": "https://avatars.githubusercontent.com/u/80064475?v=4" }, + { "login": "jo-chemla", "avatar_url": "https://avatars.githubusercontent.com/u/16822841?v=4" }, + { "login": "joser93", "avatar_url": "https://avatars.githubusercontent.com/u/6912089?v=4" }, + { "login": "justijndepover", "avatar_url": "https://avatars.githubusercontent.com/u/9008623?v=4" }, + { "login": "leandroscardua", "avatar_url": "https://avatars.githubusercontent.com/u/24698541?v=4" }, + { "login": "mairas", "avatar_url": "https://avatars.githubusercontent.com/u/407010?v=4" }, + { "login": "itzTheMeow", "avatar_url": "https://avatars.githubusercontent.com/u/50887230?v=4" }, + { "login": "NicolasNewman", "avatar_url": "https://avatars.githubusercontent.com/u/16135852?v=4" }, + { "login": "NikeLaosClericus", "avatar_url": "https://avatars.githubusercontent.com/u/39810627?v=4" }, + { "login": "noahcroghan", "avatar_url": "https://avatars.githubusercontent.com/u/27422774?v=4" }, + { "login": "ohmzi", "avatar_url": "https://avatars.githubusercontent.com/u/6551272?v=4" }, + { "login": "Rhiz3K", "avatar_url": "https://avatars.githubusercontent.com/u/33246262?v=4" }, + { "login": "saschabuehrle", "avatar_url": "https://avatars.githubusercontent.com/u/47737812?v=4" }, + { "login": "CrazyWolf13", "avatar_url": "https://avatars.githubusercontent.com/u/96661824?v=4" }, + { "login": "VIVAAN-DHAWAN", "avatar_url": "https://avatars.githubusercontent.com/u/150339722?v=4" }, + { "login": "generalmat82", "avatar_url": "https://avatars.githubusercontent.com/u/110256073?v=4" }, + { "login": "lthomsen", "avatar_url": "https://avatars.githubusercontent.com/u/28560325?v=4" }, + { "login": "pitschi", "avatar_url": "https://avatars.githubusercontent.com/u/6841565?v=4" }, + { "login": "sharpsalat", "avatar_url": "https://avatars.githubusercontent.com/u/15666932?v=4" }, + { "login": "tech62", "avatar_url": "https://avatars.githubusercontent.com/u/16237642?v=4" }, + { "login": "AartSchinkel", "avatar_url": "https://avatars.githubusercontent.com/u/189675191?v=4" }, + { "login": "afonsojramos", "avatar_url": "https://avatars.githubusercontent.com/u/19473034?v=4" }, + { "login": "m0s4ik", "avatar_url": "https://avatars.githubusercontent.com/u/26578395?v=4" }, + { "login": "ashtonbatty", "avatar_url": "https://avatars.githubusercontent.com/u/230635?v=4" }, + { "login": "Oupsman", "avatar_url": "https://avatars.githubusercontent.com/u/11260343?v=4" }, + { "login": "cethien", "avatar_url": "https://avatars.githubusercontent.com/u/60463918?v=4" }, + { "login": "DZ945brH", "avatar_url": "https://avatars.githubusercontent.com/u/42635243?v=4" }, + { "login": "dgshue", "avatar_url": "https://avatars.githubusercontent.com/u/12952156?v=4" }, + { "login": "d-lindahl", "avatar_url": "https://avatars.githubusercontent.com/u/690410?v=4" }, + { "login": "KartulUdus", "avatar_url": "https://avatars.githubusercontent.com/u/23346150?v=4" }, + { "login": "ieugen", "avatar_url": "https://avatars.githubusercontent.com/u/1050920?v=4" }, + { "login": "faugusto-oliveira", "avatar_url": "https://avatars.githubusercontent.com/u/37384074?v=4" }, + { "login": "frankvHoof93", "avatar_url": "https://avatars.githubusercontent.com/u/7346516?v=4" }, + { "login": "febrile42", "avatar_url": "https://avatars.githubusercontent.com/u/14597122?v=4" }, + { "login": "Kaotic3", "avatar_url": "https://avatars.githubusercontent.com/u/80522225?v=4" }, + { "login": "KelianB", "avatar_url": "https://avatars.githubusercontent.com/u/11216155?v=4" }, + { "login": "hotrungnhan", "avatar_url": "https://avatars.githubusercontent.com/u/40029631?v=4" } +] diff --git a/apps/docs/static/data/translation-contributions.json b/apps/docs/static/data/translation-contributions.json index 5818e6339..1c89663dd 100644 --- a/apps/docs/static/data/translation-contributions.json +++ b/apps/docs/static/data/translation-contributions.json @@ -1 +1,966 @@ -[{"username":"carlchina","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/6697/medium/d22bbe7797bbeb30dbdc73a5648d329a_default.png"},{"username":"zielmann","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/7795/medium/ad22b8b8d5eb33e4154d53a454c862fd_default.png"},{"username":"Thalyn","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12494028/medium/5faf5acc945a874ed116c4567edaa09f_default.png"},{"username":"magnushj","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12503488/medium/68f32e33ea7b891960055c9f831f7344_default.png"},{"username":"almontegil","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12580457/medium/f4136cacbdfdb4c28ae7f85dc5f840db_default.png"},{"username":"andibing","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12664938/medium/b8be63e4dcb2e791ced1ffc9e3a049a5.jpg"},{"username":"gronare","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12680911/medium/c6eb14d1504156f34a158e507f73aa3d_default.png"},{"username":"SmartPhoneLover","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12701640/medium/ec95486662ec875cda080e778c3ff702.jpg"},{"username":"marcelotk_15","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12773227/medium/ecf6bea16ab0c873c131df2154ee9718_default.png"},{"username":"S3OD177","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13051544/medium/11dd990837f61f7e8f7d36b041a7fddb_default.png"},{"username":"marcg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13153301/medium/ebcf60fbf27deb148ec40a659566c6ff_default.png"},{"username":"BeersTeddy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13185230/medium/2f1f4e1effe74a23422b195cbefb2a95_default.png"},{"username":"jamesmcmahon0","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13245578/medium/586aa873b4abddbd9abc6f3de99ab70e.jpeg"},{"username":"b1nar10","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13286752/medium/249b02e3368752cb175446082015737c_default.png"},{"username":"vannCN","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13330448/medium/9b8a9ee3611e51e951e22d5fd4eb7d8d.jpg"},{"username":"binswm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13343482/medium/45dde0e6097b9b72705d2eba9dbbc276_default.png"},{"username":"SkewRam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13496556/medium/188f5c2deb7938eda51eb786cc4539ca.jpeg"},{"username":"raphcatarino","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13547726/medium/b003511e67df13a4b4b5689488fa8099.jpg"},{"username":"shillos5","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13600557/medium/b17650b2b84f829d54fa548c44c1ab27.jpeg"},{"username":"wolong98","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13641407/medium/f4634edc58c7857a357e5293543c15cf.jpg"},{"username":"spair0039","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14012333/medium/72430e96027c09c19141cac38eae4617.png"},{"username":"MajorMarcin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14072183/medium/0a197e64bb92b6ea94cecbb607512c45.jpg"},{"username":"KosmoMoustache","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14103535/medium/51c438cdd9f86e8811c75f4869de479c.png"},{"username":"Soochaehwa","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14118689/medium/496a1ce63111547bf455a1e0a7ac75f1_default.png"},{"username":"garryfield","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14187035/medium/520c964706676045f6eeec1b08edc880.jpg"},{"username":"droidenko","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14444264/medium/4aa3a8e824f72bc9e5ec0d8de307095e.jpeg"},{"username":"maathis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14489950/medium/6eeddf13a757ee35f78f1763f94d95e1.jpeg"},{"username":"bukvam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14546502/medium/a819dc40a13c57395a17dc46e847d3ce.jpg"},{"username":"gm.cinalli","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14670666/medium/2d466a0fdbda40764526be86c97c0ab4.jpeg"},{"username":"antoine2tt","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14722148/medium/f88d926900862dd59007ea4b3419cb9d.png"},{"username":"cretzen","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14799754/medium/3ba5c1805ec20c000d5810c07985afe9.jpg"},{"username":"ktKongTong","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14817246/medium/97cfc3c028dbdaf85ebd1102da71e58c.jpeg"},{"username":"marinkaberg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14861042/medium/2d5c4e62613f03082f3e645fa92efd59.jpeg"},{"username":"djismgaming","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14934947/medium/f5a8570713c34ab0f7d5405d105e2a9a.jpeg"},{"username":"f1refa11","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14949159/medium/fd2ae63b8eb4462200ba96abf943c1b9.png"},{"username":"jeffersonraimon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15057621/medium/6dff469563860e2618bc9d45646d0ab4.png"},{"username":"giop98","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15057987/medium/b8a4825d3fc39fc662f35ee258db4b2d.jpeg"},{"username":"tomislav.kraljevic","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15118857/medium/e133f1061cc92850b854d05d8faaeafd.png"},{"username":"Walkx","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15202182/medium/5c37361ae45aeed487b34582c1f7ca37.png"},{"username":"andrea.rosso","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15246318/medium/11f3f5ef44ec7f55b6f143090e208704_default.png"},{"username":"ajnart","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15270132/medium/a0f107a463c8910ee96bc2fa843a17e3.jpeg"},{"username":"Witchling","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15282238/medium/9e196b6783415b10ca571b7673c2ef33.jpg"},{"username":"guineuu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15292058/medium/22fbb758bda3b7805d50bf21d38f2c20.jpeg"},{"username":"Bulgus","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15304568/medium/0e8787e5ceb02ed5c96a514d0068ae87.jpg"},{"username":"Narno","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15314996/medium/a6ba093f24884250a1bf6c6f2ca50f1b_default.png"},{"username":"BySempron","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15315986/medium/e3d22d7b1423c6823a9f36d595ed4bdb.png"},{"username":"jonathan.berglin.work","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15359236/medium/95930b2093db13b76179782f7322c5d5.png"},{"username":"icdmkg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15405504/medium/f334d16cde1ac4ffb935b440d03465af.gif"},{"username":"irithys","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15405614/medium/3086461c47cce0a0c031925e5f943412.png"},{"username":"JannesV","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419912/medium/a7809eb4b817d7c49b62cf10ae86b950.png"},{"username":"benniblot","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419914/medium/8086b1573d31f152ba41949b3a172445.jpeg"},{"username":"pacjo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419916/medium/3cbeddbd7bc01faafb5a3bf47bba915b_default.png"},{"username":"Payou6994","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419934/medium/37c9b9b17dfb578404c1c1ddb73ba7a8.png"},{"username":"fzibi21","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15419976/medium/0da688450358e0290a7b7359cc1f7328.png"},{"username":"WowMurdock","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420118/medium/de19576fccb495b6dfe4c4c04a56b834.png"},{"username":"hbooo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420120/medium/6c7c7f8db785061356ebb03d044d3329.jpeg"},{"username":"Manicraft1001","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420178/medium/50ec94563a06a9f74f33bd09f01eed4d.jpg"},{"username":"Void123","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15420354/medium/86929d44df92a00f9fe900a985c196df_default.png"},{"username":"R4cc","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15422606/medium/a390979662b84694f59de30bdb732141.jpeg"},{"username":"fabricionaweb","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15425808/medium/a9354142e7ae5152c144409d55fda551_default.png"},{"username":"JokeOfDead","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15426890/medium/a383eac9365e9de64fd4ab1d6fd0cb95.jpeg"},{"username":"hkz","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15427174/medium/c88acefb0d7306e1f7470e872029fb39_default.png"},{"username":"Steken","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15428516/medium/d5aea5653c769c3a523182bdb60d1664.png"},{"username":"flar.anton","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15428592/medium/b01fdb365d892e9f811f77fcb50a80a2.jpeg"},{"username":"Bon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15433542/medium/5397da4dfc821f20b6ac14fe0c514e9a.jpeg"},{"username":"bfkadan","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15434162/medium/4f9a0b43cfe3acaea60124c14ba7f44a.png"},{"username":"BunnySweety","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15434662/medium/f0ef200a6a0dcf0e1d0e9ecd4148f560_default.png"},{"username":"HRKings","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15436168/medium/69a31e461d38549f01864e7ef10d642e.png"},{"username":"wiston81","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15439078/medium/10f292c8d12a7c21a44b54495fa4a3d8.jpeg"},{"username":"qaz0911","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15440860/medium/3d3e50ee388c72dc4bf7a771761f2d89_default.png"},{"username":"qqyule","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15441462/medium/7a3cdf82710ffb5d8f388bc0bd010665.png"},{"username":"Bims0n","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15445560/medium/603220b603eeb3367e0f0d3fa675247c.jpg"},{"username":"TariqDaCoder","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15446228/medium/50b0f4040112bbd67690b769477398e5_default.png"},{"username":"Anarchon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15449644/medium/e925e1f3e3ffbf0f982391ce263a1a28.jpeg"},{"username":"Ashun","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15453020/medium/ccdcf51c73d6aae40751bb30beee1915_default.png"},{"username":"sebekmartin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15454038/medium/bcfb44598cdfd1d7cd4eb35812538962.jpeg"},{"username":"RagnarGraves","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15459882/medium/143d5af850c1154070a218bea124e9cb_default.png"},{"username":"PrtmPhlp","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15462414/medium/b80db55e9de301432dcd1f8c8b24fd49_default.png"},{"username":"DooYoo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15470768/medium/2a18cf4be67094724b508c9e1e698a21_default.png"},{"username":"espentruls","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15486092/medium/8e38afc3a4ff669226a0cfd3e420ff3a.jpeg"},{"username":"frisco82","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15486922/medium/4e1c5d4189b42508e660daa3c1c25b2a.jpeg"},{"username":"lupineDK","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15491798/medium/461bd501e8371c062bf29ea171aedd36_default.png"},{"username":"hillaliy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15492732/medium/0bae17b421604892d888e3fc70cf0587.jpeg"},{"username":"MarcOrfilaCarreras","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15501072/medium/ea52b26c3c6f21e4931e38e3ce3f3d6e.png"},{"username":"robertbridda","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15507822/medium/a368c2e30411bb2da9b49290084191f3.png"},{"username":"MKoniuszko","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15518090/medium/87605434fcc839f6763ab07c50f6d232.jpeg"},{"username":"HeroSizy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15518710/medium/4e79c0e98cbeb536dd961e656331b509.png"},{"username":"dwt136","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15520022/medium/554422503f2baea43ace85facb4546fb_default.png"},{"username":"asifthewebguy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15526719/medium/b18931dd0c800d725048bd440646198b_default.png"},{"username":"eiloogs","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15545537/medium/f290a2f1190983530a9b76b2e858a609.gif"},{"username":"_vytdv","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15547289/medium/60d8644cc8ad6f11a92ccea4a14cd098_default.png"},{"username":"crendasien","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15554645/medium/598ab1d4aaf6b8dccd5ba16be92da7b9.jpeg"},{"username":"edxo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15573823/medium/8a565b732a75a77f840dd123cdb30bf4.png"},{"username":"somerlev","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15617065/medium/f4b13513e311ec902d90b2f718412c55.jpg"},{"username":"kid1412621","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15643771/medium/dd455e32de652fa88e6fd97598bdffa7.png"},{"username":"suming","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15644717/medium/244159dfe10fa03436205506f80c9e25.png"},{"username":"nick.gher","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15647517/medium/5374a2c6fef60a3fbf0edf86b997c351_default.png"},{"username":"DataCat","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15650315/medium/ce7c1365adf35c5d490d77500a4607fb_default.png"},{"username":"dizo89","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15658375/medium/0ca745e5017d491fe1b22b0239904de8.jpeg"},{"username":"tee_noodle","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15674577/medium/804d9cf06f5196026acb6436b809d0da_default.png"},{"username":"Marty88","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15674593/medium/492b1509d52bd2809dea768121217125.jpeg"},{"username":"Spillebulle","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15677023/medium/20b98bb85062e07afe0e63618f8a5feb.PNG"},{"username":"petitmewen","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15685239/medium/15de9b62d2e0bc25013435f1784bbcc1.jpeg"},{"username":"NoProsNoNoobs","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15687709/medium/ae8f65fafeb8bcf74dcb8871bbe46461.png"},{"username":"y.gybson","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15690777/medium/b5cb5d2d5768904ff6586c727e3a6c77.jpeg"},{"username":"inside90","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15704947/medium/c1355fcb30dd76f8e39d98d1d49f1c52.png"},{"username":"RJSkudra","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15709853/medium/c3abf2774913dc4e81fb261d36d7668c.png"},{"username":"binge203","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15713937/medium/77c1cfa4314673db80e6881fd9f64668.gif"},{"username":"Mailootje","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15714337/medium/743c3bc4ab1989966a375eeeec83d8b8.jpeg"},{"username":"tim-wiegers","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15719805/medium/08a96f064813350661cd6b20bf3d7d99.png"},{"username":"GkhnG","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15722911/medium/71a027caec489ef6ce82bcf1888329d0_default.png"},{"username":"Zoen-Millo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15760967/medium/9e956f11adc5b34f5636268b5c485dbf.jpg"},{"username":"HooinKyoma","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15792897/medium/9489f0a9b368e0e827ae758b740a2eed.jpeg"},{"username":"wathergeen","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15794495/medium/a83b7fc80d180669ebfd6deb3544cfd0.png"},{"username":"MoeToo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15818233/medium/d35cd6953717706eaf20f6c143c62947.png"},{"username":"itodouble","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15836233/medium/e984caea18fb0673bf319fcf28cef649.png"},{"username":"loslocitos","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15847901/medium/fe30d12fd2cf38212f929e13b169f9ec.jpeg"},{"username":"Oversleep","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15849065/medium/06141f13a6d541d753f3c2f2947b8068_default.png"},{"username":"Beardy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15865139/medium/fca6b9d2b3f52e286d1568f52b83b6a0_default.png"},{"username":"raelyan","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15875457/medium/2f4fda1d1aaa5dcc79b328baf3f03151.jpeg"},{"username":"dolphin738","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15913763/medium/ee6fede7b8528ca642329ada80d1cc18.png"},{"username":"brunotco","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15916719/medium/09db45880fc05abc18adb8d932a5ecf9_default.png"},{"username":"LukeIsHereToDevelop","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15924739/medium/3e6cd3940297bb4ba7bb039c93e6f918.png"},{"username":"kennit","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15925879/medium/6b0733ad3c5949b91c55e4d8b03db8a5_default.png"},{"username":"kuunpire","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15950309/medium/8192a4f08f07086828ac9f74ed29a169.jpeg"},{"username":"Sandor-dev","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15951759/medium/0216c2da4eb028164ebbecf1c72f6271_default.png"},{"username":"Meierschlumpf","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15953187/medium/23c744faef1ab84fbdc9351a7850aab6.jpeg"},{"username":"harmlesscat","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15970733/medium/dd8d0214a0250c932bb518b1b55e45a2_default.png"},{"username":"OrzWTF","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15976121/medium/4c4557cbff7ff7b0503455bc59c020e0.jpeg"},{"username":"tagaishi","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15977271/medium/eade504c83a5a1ff831c80a538fbdb44_default.png"},{"username":"azurite928","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15981895/medium/547ccc459ee123e78b5401c499f1022d.png"},{"username":"Ronner231","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16021342/medium/7734d550df2de5a2fec2ffff33e7024c.jpeg"},{"username":"ugyes","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16034148/medium/ed001e3f470a2dea9a8ce955b18e7bd5.png"},{"username":"rpieja","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16045554/medium/bd55baca2ef8b92502a760cc9ee7c505_default.png"},{"username":"flambyisyou","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16051620/medium/3a3bc0c90f6b95ab4ef74396a0a17beb.png"},{"username":"Topbcy","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16077170/medium/d3aed33ea56330338756cfcd89477cfe.jpeg"},{"username":"ai5d02sb","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16084674/medium/7c8119fe2a5ca71bb15f636916a42b95_default.png"},{"username":"explosiveparrot","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16097722/medium/7762f80fc1da63f5b2eb87de9d640324_default.png"},{"username":"DestroyCom","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16111544/medium/83e3d3ac5c8bfed634cd1a074854db67.png"},{"username":"neotraxo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16116966/medium/b30df957873329019a8a90a69f6efe3a.png"},{"username":"gzxpa","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16123314/medium/487b05577310a946b0b98bc72c11213b_default.png"},{"username":"TORIK","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16124732/medium/de770890e6411860ac06e8cc2dc0abd0_default.png"},{"username":"sergio.pibot","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16138114/medium/80db802b2fcd6bbf19ea4c7413367dca.jpeg"},{"username":"karam-ajaj","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16139838/medium/7539ab958d3c85d5f67e7849483ea8f7.jpeg"},{"username":"SimonHenz97","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16151520/medium/9b94a85b536688e2d94538c384fd0a76.png"},{"username":"olsson82","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16198988/medium/eeaab4cba210c537424d4204754b604e.png"},{"username":"bo3bdo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16222806/medium/8652f3beacb6098dde5a4cd0a29fe80d.jpeg"},{"username":"AngryPlayer04","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16245192/medium/342715274f4dc31fd4132cdae9126188.jpeg"},{"username":"ehatamm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16245884/medium/979d5e5526fe545be9bf46db481f7182.jpeg"},{"username":"Balionelis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16246058/medium/986d62ba363594c517d966fe9178dcbb.png"},{"username":"kwargs","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16248816/medium/19ce11f04bf1ae2637e0483399c675f9_default.png"},{"username":"lucicu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16273892/medium/3b09e8f3bead221ef98d6a45a16851dc_default.png"},{"username":"Michael5564445","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16357688/medium/9d9026a8bf3eaccb0417da240932ebf7.png"},{"username":"Netscream","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16359198/medium/694e0c8572dc8a47e6d63da31ec5b992.png"},{"username":"belicstefan04","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16368142/medium/4742dcfd7bf7ad7e33e37ac44fba7e0f.png"},{"username":"Hamad2066","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16371478/medium/f37bbc7685b6757defdbd1494236af61.jpeg"},{"username":"3ct0pl4sm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16399616/medium/ce796d1c40163975624c0a483e56374f.png"},{"username":"sanchez.marcell626","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16433865/medium/3ddde1314764cc2205ffdcd1ae719a91.png"},{"username":"Minoctis","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16490079/medium/91fd0849303a4eca033d660d0a7b6854.jpeg"},{"username":"homarr","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16657003/medium/3afabfd3de949a54ff5d40ad04552aba.png"},{"username":"mwgg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16658379/medium/763dd09f5c238cc5324d4d5357985292.png"},{"username":"kiwinho","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16671855/medium/bfe3a2d497dc4748a04d02e4ae2139cb.jpeg"},{"username":"tjvg4m34r13","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16679135/medium/7a483b9b0abe0d925e54808e1cb38fa0.jpeg"},{"username":"Diegoem","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16705921/medium/29ce68ebc191fc3f65499511b12de98f_default.png"},{"username":"bouks69","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16746091/medium/b58b1fc08520de416198be9df5d093eb.jpeg"},{"username":"futhgar","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16748067/medium/b8c526b097f9aa9d687250cac3df16dc.jpeg"},{"username":"GrimSQL","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16764343/medium/fff729a76d1f8fbcdaee9bb0c0f5f3fd.png"},{"username":"chnikel","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16767047/medium/3dda2a37e03049dafefe6697bb00f75c.png"},{"username":"yuki19870616","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16767951/medium/f59c848e38382cda6c8464b0a7b9e642_default.png"},{"username":"noamdal","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16782245/medium/b4a72a61f9caf138f0322c0cb987e6d0.png"},{"username":"MalithRukshan","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16809057/medium/084d6a5b35fbbeacc70e7021197d222f.png"},{"username":"minirope19","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16930929/medium/e8cbbc26747e31c5a8959215e1dd067b.jpeg"},{"username":"prubin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17503492/medium/96ac87644691e49c1f983f2f094e541c_default.png"},{"username":"sam-tam-sam","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17578052/medium/1628dc2954ce3ae95e0caaa2bd60ab0c.png"},{"username":"toineenzo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12371852/medium/9f1b2bedb4794c59479cd289bdba9fab.png"},{"username":"ArcaneWater","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12421105/medium/1ac82517a6c658f6b62c48aebcb17e86_default.png"},{"username":"Ebedami","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/12974801/medium/b596dea5c09454c4c828eac558389755.jpg"},{"username":"perrygamerptyt","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13117177/medium/1406c949507ecd438480473c8a1f6124.jpg"},{"username":"SergiSvK","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13320543/medium/3df3c79cc5f0c53716c559cd3fd2fc20.png"},{"username":"jeongeon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13362856/medium/eb572f72cde5e5526c517ca3a6489850_default.png"},{"username":"MrTranCFCVN","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13439475/medium/a1789d69c85d90c667194b5d6a518c08_default.png"},{"username":"Tobost06","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13467449/medium/9227dc07f6366bc060d28304f5cb8ce7.jpeg"},{"username":"Kf637","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13530622/medium/118b00bb72d01d3229c97409637e25d1_default.png"},{"username":"Cruellest","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/13610615/medium/2a74faa0947ee08d18f7946fb8602c1e.jpg"},{"username":"olavinto","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14424644/medium/37c01732bd2b7a272b421807a05ccfeb.png"},{"username":"Thario","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14491372/medium/dd5e142070802a672900121aa3f332a6_default.png"},{"username":"Wjouter","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14585620/medium/b91a51513332bdc0a0a9ecbed99ecbc3.png"},{"username":"albanobattistella","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14686194/medium/564afcfd76f5cd24751bd669cf4943aa.jpg"},{"username":"Kachelkaiser","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14763406/medium/203a781797da4a18fe0f4e7db8fd547c.png"},{"username":"regi4","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14842936/medium/f7e1d672f562a7db61ba6b4b8f4de41d.png"},{"username":"baton5129","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/14891064/medium/8d438f557b82977dd02f0ead3187265f.PNG"},{"username":"meviper","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/15958903/medium/209f521ce33a05831fa8d7d1b7babc20_default.png"},{"username":"GerOriki","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16268376/medium/da00e54b08cd40348231d92873a0cd0a_default.png"},{"username":"TheRedCyclops","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16486399/medium/7f39226180120d5a9efcb8e13d8aec8e_default.png"},{"username":"dymek37","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16659221/medium/d1dc6d11d7e7fc370efc5070e837ae03.png"},{"username":"B3CKDOOR","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16744975/medium/e6c7b2d45e76465d54e6efb67c83da7d.png"},{"username":"Larsluph","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16779933/medium/ed7d36f8b44013bad3a16ac0491bd0f7.png"},{"username":"FOEDI","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16781001/medium/6b4552fb72e359aa016f7a054078fac8.png"},{"username":"xmarkurion","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16805443/medium/34a20428427de5aaef99c7d140646803.png"},{"username":"gregid","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16806705/medium/f3c8f4a20436e8538929130142bbc104.png"},{"username":"Flameberg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16820453/medium/d47be866148474c9d05fec6fbe406d88.png"},{"username":"Playfust","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16872865/medium/5f4609cc711e5fb9fa8a0b178635769c.jpeg"},{"username":"Cotignac","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16879297/medium/81ff353edf030699a159bb79cda26e84.jpg"},{"username":"LeaHun","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16916375/medium/618520f0543b1e212ebc83d66b683d4b_default.png"},{"username":"jackwellerreal","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16919717/medium/37bbfdc03893f141133ccc619593266d.png"},{"username":"renan.costaalencar","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16938427/medium/6d25b25320c5bde734118dec4af9cd5b.png"},{"username":"andrius.cim","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/16967845/medium/46028fc1a0ddfaaeebcb37b39739625d_default.png"},{"username":"xjxexrxrxyx","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17041412/medium/d34d664166db6fb25579bca9ff3b50b4.jpeg"},{"username":"bilhal.fellah","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17044572/medium/d1ec6f17e4aa013e9eededc83778d2c6.png"},{"username":"the_octo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17058060/medium/7423ab3a4cabb67f5decb2e2dfa2b675_default.png"},{"username":"BamesJond","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17075846/medium/128d7ffd40254c8e376f45678e2fc620_default.png"},{"username":"Kornikus","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17134240/medium/d7a42b2c30db46ff152699ca01f9e11a_default.png"},{"username":"xoxyuxu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17176526/medium/108055aa24343043de852e412bec74be.png"},{"username":"cryptodntsleep","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17249408/medium/b9e15aa2b24a0dbc1e4f194aa8ed5109.png"},{"username":"yaniorg","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17261842/medium/7dbfc77f21c826845961243c44540d26.jpg"},{"username":"Vidariondr","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17262438/medium/45fbc71be02ef27296b6f423e97b6a03_default.png"},{"username":"Fastery","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17263066/medium/701b0edc59676174863ad651528bbb37.jpeg"},{"username":"stratself","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17290388/medium/57d9d8161b3fd0abf4dc5558b4a1fa05_default.png"},{"username":"wuzeqin","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17292606/medium/b9e0308410b31337e2d7aa6ed346d718_default.png"},{"username":"ChristopherBull","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17304338/medium/21a175ce596bfae81430767467908b90.jpeg"},{"username":"darkbcnlord","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17311436/medium/b271bc0b419ec3a26ddb7b63ff8ffc4b.png"},{"username":"zhoran1997","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17344028/medium/c8f450b5a8f1e9494a45dc60af7ce63e.png"},{"username":"gilalves1703","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17447768/medium/3f1de562a5c2391c88bbf8d5cf40a266.png"},{"username":"iServeCloud","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17470960/medium/11649b99d609438d66455a4d2fdc70f7.png"},{"username":"guibolzantvbox","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17474136/medium/59a576e6da538664ceb972253916fa02.jpeg"},{"username":"ivann136","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17506062/medium/67d09ada36fac5f444a1f7517e3a97bd_default.png"},{"username":"Maheshivara","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17516082/medium/576e1e6581cf969615b265de6aeff8b7.jpeg"},{"username":"brunogui81","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17517542/medium/7c0d174e810435af518fe8e0c05e151f.jpeg"},{"username":"michelwilhelm","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17542190/medium/4c6b33fd8993ff565fa75add2ce8355e.jpeg"},{"username":"dias-gxstavo","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17547376/medium/8c6b109aae8aeb651192346a39ae9e5b.jpeg"},{"username":"ToxykAuBleu","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17614030/medium/8d21e0608560172b121bd46126d827c7.jpeg"},{"username":"e.erdemir","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17617994/medium/7259a29db9941c6171a8cbbd643b92bd.png"},{"username":"sjonkreutz","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17618306/medium/7601c45d015189a863656e21348d223b.png"},{"username":"volovich0377","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17620388/medium/c929a8fbd24f96d17620fa497ade7309.png"},{"username":"Hamstio1","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17624898/medium/406e0bf40094c24a01c3064f8f5b2a82.png"},{"username":"i3laa","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17627462/medium/613a9d283ed8b69819ee181903851660.jpeg"},{"username":"bastiengrignon","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17629884/medium/ddfc3339285bd65195fcd834e512e9b7.jpeg"},{"username":"kauhee","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17644600/medium/def1b9066cf9275b4273a5a5dca7f325.png"},{"username":"hongminzheng","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17683860/medium/a764f4963912777d27a7cd98e136a2b2.png"},{"username":"d-lindahl","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17726729/medium/cbde348582fbabcfadd89a56cd5a0b40.png"},{"username":"Enoal-Fauchille-Bolle","avatarUrl":"https://crowdin-static.cf-downloads.crowdin.com/avatar/17734649/medium/6e6fb29198782dc7856ea21811db669c.jpeg"}] \ No newline at end of file +[ + { + "username": "carlchina", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/6697/medium/d22bbe7797bbeb30dbdc73a5648d329a_default.png" + }, + { + "username": "zielmann", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/7795/medium/ad22b8b8d5eb33e4154d53a454c862fd_default.png" + }, + { + "username": "Thalyn", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/12494028/medium/5faf5acc945a874ed116c4567edaa09f_default.png" + }, + { + "username": "magnushj", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/12503488/medium/68f32e33ea7b891960055c9f831f7344_default.png" + }, + { + "username": "almontegil", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/12580457/medium/f4136cacbdfdb4c28ae7f85dc5f840db_default.png" + }, + { + "username": "andibing", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/12664938/medium/b8be63e4dcb2e791ced1ffc9e3a049a5.jpg" + }, + { + "username": "gronare", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/12680911/medium/c6eb14d1504156f34a158e507f73aa3d_default.png" + }, + { + "username": "SmartPhoneLover", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/12701640/medium/ec95486662ec875cda080e778c3ff702.jpg" + }, + { + "username": "marcelotk_15", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/12773227/medium/ecf6bea16ab0c873c131df2154ee9718_default.png" + }, + { + "username": "S3OD177", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13051544/medium/11dd990837f61f7e8f7d36b041a7fddb_default.png" + }, + { + "username": "marcg", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13153301/medium/ebcf60fbf27deb148ec40a659566c6ff_default.png" + }, + { + "username": "BeersTeddy", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13185230/medium/2f1f4e1effe74a23422b195cbefb2a95_default.png" + }, + { + "username": "jamesmcmahon0", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13245578/medium/586aa873b4abddbd9abc6f3de99ab70e.jpeg" + }, + { + "username": "b1nar10", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13286752/medium/249b02e3368752cb175446082015737c_default.png" + }, + { + "username": "vannCN", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13330448/medium/9b8a9ee3611e51e951e22d5fd4eb7d8d.jpg" + }, + { + "username": "binswm", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13343482/medium/45dde0e6097b9b72705d2eba9dbbc276_default.png" + }, + { + "username": "SkewRam", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13496556/medium/188f5c2deb7938eda51eb786cc4539ca.jpeg" + }, + { + "username": "raphcatarino", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13547726/medium/b003511e67df13a4b4b5689488fa8099.jpg" + }, + { + "username": "shillos5", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13600557/medium/b17650b2b84f829d54fa548c44c1ab27.jpeg" + }, + { + "username": "wolong98", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13641407/medium/f4634edc58c7857a357e5293543c15cf.jpg" + }, + { + "username": "spair0039", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14012333/medium/72430e96027c09c19141cac38eae4617.png" + }, + { + "username": "MajorMarcin", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14072183/medium/0a197e64bb92b6ea94cecbb607512c45.jpg" + }, + { + "username": "KosmoMoustache", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14103535/medium/51c438cdd9f86e8811c75f4869de479c.png" + }, + { + "username": "Soochaehwa", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14118689/medium/496a1ce63111547bf455a1e0a7ac75f1_default.png" + }, + { + "username": "garryfield", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14187035/medium/520c964706676045f6eeec1b08edc880.jpg" + }, + { + "username": "droidenko", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14444264/medium/4aa3a8e824f72bc9e5ec0d8de307095e.jpeg" + }, + { + "username": "maathis", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14489950/medium/6eeddf13a757ee35f78f1763f94d95e1.jpeg" + }, + { + "username": "bukvam", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14546502/medium/a819dc40a13c57395a17dc46e847d3ce.jpg" + }, + { + "username": "gm.cinalli", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14670666/medium/2d466a0fdbda40764526be86c97c0ab4.jpeg" + }, + { + "username": "antoine2tt", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14722148/medium/f88d926900862dd59007ea4b3419cb9d.png" + }, + { + "username": "cretzen", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14799754/medium/3ba5c1805ec20c000d5810c07985afe9.jpg" + }, + { + "username": "ktKongTong", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14817246/medium/97cfc3c028dbdaf85ebd1102da71e58c.jpeg" + }, + { + "username": "marinkaberg", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14861042/medium/2d5c4e62613f03082f3e645fa92efd59.jpeg" + }, + { + "username": "djismgaming", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14934947/medium/f5a8570713c34ab0f7d5405d105e2a9a.jpeg" + }, + { + "username": "f1refa11", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14949159/medium/fd2ae63b8eb4462200ba96abf943c1b9.png" + }, + { + "username": "jeffersonraimon", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15057621/medium/6dff469563860e2618bc9d45646d0ab4.png" + }, + { + "username": "giop98", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15057987/medium/b8a4825d3fc39fc662f35ee258db4b2d.jpeg" + }, + { + "username": "tomislav.kraljevic", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15118857/medium/e133f1061cc92850b854d05d8faaeafd.png" + }, + { + "username": "Walkx", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15202182/medium/5c37361ae45aeed487b34582c1f7ca37.png" + }, + { + "username": "andrea.rosso", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15246318/medium/11f3f5ef44ec7f55b6f143090e208704_default.png" + }, + { + "username": "ajnart", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15270132/medium/a0f107a463c8910ee96bc2fa843a17e3.jpeg" + }, + { + "username": "Witchling", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15282238/medium/9e196b6783415b10ca571b7673c2ef33.jpg" + }, + { + "username": "guineuu", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15292058/medium/22fbb758bda3b7805d50bf21d38f2c20.jpeg" + }, + { + "username": "Bulgus", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15304568/medium/0e8787e5ceb02ed5c96a514d0068ae87.jpg" + }, + { + "username": "Narno", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15314996/medium/a6ba093f24884250a1bf6c6f2ca50f1b_default.png" + }, + { + "username": "BySempron", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15315986/medium/e3d22d7b1423c6823a9f36d595ed4bdb.png" + }, + { + "username": "jonathan.berglin.work", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15359236/medium/95930b2093db13b76179782f7322c5d5.png" + }, + { + "username": "icdmkg", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15405504/medium/f334d16cde1ac4ffb935b440d03465af.gif" + }, + { + "username": "irithys", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15405614/medium/3086461c47cce0a0c031925e5f943412.png" + }, + { + "username": "JannesV", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15419912/medium/a7809eb4b817d7c49b62cf10ae86b950.png" + }, + { + "username": "benniblot", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15419914/medium/8086b1573d31f152ba41949b3a172445.jpeg" + }, + { + "username": "pacjo", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15419916/medium/3cbeddbd7bc01faafb5a3bf47bba915b_default.png" + }, + { + "username": "Payou6994", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15419934/medium/37c9b9b17dfb578404c1c1ddb73ba7a8.png" + }, + { + "username": "fzibi21", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15419976/medium/0da688450358e0290a7b7359cc1f7328.png" + }, + { + "username": "WowMurdock", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15420118/medium/de19576fccb495b6dfe4c4c04a56b834.png" + }, + { + "username": "hbooo", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15420120/medium/6c7c7f8db785061356ebb03d044d3329.jpeg" + }, + { + "username": "Manicraft1001", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15420178/medium/50ec94563a06a9f74f33bd09f01eed4d.jpg" + }, + { + "username": "Void123", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15420354/medium/86929d44df92a00f9fe900a985c196df_default.png" + }, + { + "username": "R4cc", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15422606/medium/a390979662b84694f59de30bdb732141.jpeg" + }, + { + "username": "fabricionaweb", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15425808/medium/a9354142e7ae5152c144409d55fda551_default.png" + }, + { + "username": "JokeOfDead", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15426890/medium/a383eac9365e9de64fd4ab1d6fd0cb95.jpeg" + }, + { + "username": "hkz", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15427174/medium/c88acefb0d7306e1f7470e872029fb39_default.png" + }, + { + "username": "Steken", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15428516/medium/d5aea5653c769c3a523182bdb60d1664.png" + }, + { + "username": "flar.anton", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15428592/medium/b01fdb365d892e9f811f77fcb50a80a2.jpeg" + }, + { + "username": "Bon", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15433542/medium/5397da4dfc821f20b6ac14fe0c514e9a.jpeg" + }, + { + "username": "bfkadan", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15434162/medium/4f9a0b43cfe3acaea60124c14ba7f44a.png" + }, + { + "username": "BunnySweety", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15434662/medium/f0ef200a6a0dcf0e1d0e9ecd4148f560_default.png" + }, + { + "username": "HRKings", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15436168/medium/69a31e461d38549f01864e7ef10d642e.png" + }, + { + "username": "wiston81", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15439078/medium/10f292c8d12a7c21a44b54495fa4a3d8.jpeg" + }, + { + "username": "qaz0911", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15440860/medium/3d3e50ee388c72dc4bf7a771761f2d89_default.png" + }, + { + "username": "qqyule", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15441462/medium/7a3cdf82710ffb5d8f388bc0bd010665.png" + }, + { + "username": "Bims0n", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15445560/medium/603220b603eeb3367e0f0d3fa675247c.jpg" + }, + { + "username": "TariqDaCoder", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15446228/medium/50b0f4040112bbd67690b769477398e5_default.png" + }, + { + "username": "Anarchon", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15449644/medium/e925e1f3e3ffbf0f982391ce263a1a28.jpeg" + }, + { + "username": "Ashun", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15453020/medium/ccdcf51c73d6aae40751bb30beee1915_default.png" + }, + { + "username": "sebekmartin", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15454038/medium/bcfb44598cdfd1d7cd4eb35812538962.jpeg" + }, + { + "username": "RagnarGraves", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15459882/medium/143d5af850c1154070a218bea124e9cb_default.png" + }, + { + "username": "PrtmPhlp", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15462414/medium/b80db55e9de301432dcd1f8c8b24fd49_default.png" + }, + { + "username": "DooYoo", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15470768/medium/2a18cf4be67094724b508c9e1e698a21_default.png" + }, + { + "username": "espentruls", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15486092/medium/8e38afc3a4ff669226a0cfd3e420ff3a.jpeg" + }, + { + "username": "frisco82", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15486922/medium/4e1c5d4189b42508e660daa3c1c25b2a.jpeg" + }, + { + "username": "lupineDK", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15491798/medium/461bd501e8371c062bf29ea171aedd36_default.png" + }, + { + "username": "hillaliy", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15492732/medium/0bae17b421604892d888e3fc70cf0587.jpeg" + }, + { + "username": "MarcOrfilaCarreras", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15501072/medium/ea52b26c3c6f21e4931e38e3ce3f3d6e.png" + }, + { + "username": "robertbridda", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15507822/medium/a368c2e30411bb2da9b49290084191f3.png" + }, + { + "username": "MKoniuszko", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15518090/medium/87605434fcc839f6763ab07c50f6d232.jpeg" + }, + { + "username": "HeroSizy", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15518710/medium/4e79c0e98cbeb536dd961e656331b509.png" + }, + { + "username": "dwt136", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15520022/medium/554422503f2baea43ace85facb4546fb_default.png" + }, + { + "username": "asifthewebguy", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15526719/medium/b18931dd0c800d725048bd440646198b_default.png" + }, + { + "username": "eiloogs", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15545537/medium/f290a2f1190983530a9b76b2e858a609.gif" + }, + { + "username": "_vytdv", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15547289/medium/60d8644cc8ad6f11a92ccea4a14cd098_default.png" + }, + { + "username": "crendasien", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15554645/medium/598ab1d4aaf6b8dccd5ba16be92da7b9.jpeg" + }, + { + "username": "edxo", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15573823/medium/8a565b732a75a77f840dd123cdb30bf4.png" + }, + { + "username": "somerlev", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15617065/medium/f4b13513e311ec902d90b2f718412c55.jpg" + }, + { + "username": "kid1412621", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15643771/medium/dd455e32de652fa88e6fd97598bdffa7.png" + }, + { + "username": "suming", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15644717/medium/244159dfe10fa03436205506f80c9e25.png" + }, + { + "username": "nick.gher", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15647517/medium/5374a2c6fef60a3fbf0edf86b997c351_default.png" + }, + { + "username": "DataCat", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15650315/medium/ce7c1365adf35c5d490d77500a4607fb_default.png" + }, + { + "username": "dizo89", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15658375/medium/0ca745e5017d491fe1b22b0239904de8.jpeg" + }, + { + "username": "tee_noodle", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15674577/medium/804d9cf06f5196026acb6436b809d0da_default.png" + }, + { + "username": "Marty88", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15674593/medium/492b1509d52bd2809dea768121217125.jpeg" + }, + { + "username": "Spillebulle", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15677023/medium/20b98bb85062e07afe0e63618f8a5feb.PNG" + }, + { + "username": "petitmewen", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15685239/medium/15de9b62d2e0bc25013435f1784bbcc1.jpeg" + }, + { + "username": "NoProsNoNoobs", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15687709/medium/ae8f65fafeb8bcf74dcb8871bbe46461.png" + }, + { + "username": "y.gybson", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15690777/medium/b5cb5d2d5768904ff6586c727e3a6c77.jpeg" + }, + { + "username": "inside90", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15704947/medium/c1355fcb30dd76f8e39d98d1d49f1c52.png" + }, + { + "username": "RJSkudra", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15709853/medium/c3abf2774913dc4e81fb261d36d7668c.png" + }, + { + "username": "binge203", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15713937/medium/77c1cfa4314673db80e6881fd9f64668.gif" + }, + { + "username": "Mailootje", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15714337/medium/743c3bc4ab1989966a375eeeec83d8b8.jpeg" + }, + { + "username": "tim-wiegers", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15719805/medium/08a96f064813350661cd6b20bf3d7d99.png" + }, + { + "username": "GkhnG", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15722911/medium/71a027caec489ef6ce82bcf1888329d0_default.png" + }, + { + "username": "Zoen-Millo", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15760967/medium/9e956f11adc5b34f5636268b5c485dbf.jpg" + }, + { + "username": "HooinKyoma", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15792897/medium/9489f0a9b368e0e827ae758b740a2eed.jpeg" + }, + { + "username": "wathergeen", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15794495/medium/a83b7fc80d180669ebfd6deb3544cfd0.png" + }, + { + "username": "MoeToo", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15818233/medium/d35cd6953717706eaf20f6c143c62947.png" + }, + { + "username": "itodouble", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15836233/medium/e984caea18fb0673bf319fcf28cef649.png" + }, + { + "username": "loslocitos", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15847901/medium/fe30d12fd2cf38212f929e13b169f9ec.jpeg" + }, + { + "username": "Oversleep", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15849065/medium/06141f13a6d541d753f3c2f2947b8068_default.png" + }, + { + "username": "Beardy", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15865139/medium/fca6b9d2b3f52e286d1568f52b83b6a0_default.png" + }, + { + "username": "raelyan", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15875457/medium/2f4fda1d1aaa5dcc79b328baf3f03151.jpeg" + }, + { + "username": "dolphin738", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15913763/medium/ee6fede7b8528ca642329ada80d1cc18.png" + }, + { + "username": "brunotco", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15916719/medium/09db45880fc05abc18adb8d932a5ecf9_default.png" + }, + { + "username": "LukeIsHereToDevelop", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15924739/medium/3e6cd3940297bb4ba7bb039c93e6f918.png" + }, + { + "username": "kennit", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15925879/medium/6b0733ad3c5949b91c55e4d8b03db8a5_default.png" + }, + { + "username": "kuunpire", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15950309/medium/8192a4f08f07086828ac9f74ed29a169.jpeg" + }, + { + "username": "Sandor-dev", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15951759/medium/0216c2da4eb028164ebbecf1c72f6271_default.png" + }, + { + "username": "Meierschlumpf", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15953187/medium/23c744faef1ab84fbdc9351a7850aab6.jpeg" + }, + { + "username": "harmlesscat", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15970733/medium/dd8d0214a0250c932bb518b1b55e45a2_default.png" + }, + { + "username": "OrzWTF", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15976121/medium/4c4557cbff7ff7b0503455bc59c020e0.jpeg" + }, + { + "username": "tagaishi", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15977271/medium/eade504c83a5a1ff831c80a538fbdb44_default.png" + }, + { + "username": "azurite928", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15981895/medium/547ccc459ee123e78b5401c499f1022d.png" + }, + { + "username": "Ronner231", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16021342/medium/7734d550df2de5a2fec2ffff33e7024c.jpeg" + }, + { + "username": "ugyes", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16034148/medium/ed001e3f470a2dea9a8ce955b18e7bd5.png" + }, + { + "username": "rpieja", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16045554/medium/bd55baca2ef8b92502a760cc9ee7c505_default.png" + }, + { + "username": "flambyisyou", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16051620/medium/3a3bc0c90f6b95ab4ef74396a0a17beb.png" + }, + { + "username": "Topbcy", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16077170/medium/d3aed33ea56330338756cfcd89477cfe.jpeg" + }, + { + "username": "ai5d02sb", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16084674/medium/7c8119fe2a5ca71bb15f636916a42b95_default.png" + }, + { + "username": "explosiveparrot", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16097722/medium/7762f80fc1da63f5b2eb87de9d640324_default.png" + }, + { + "username": "DestroyCom", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16111544/medium/83e3d3ac5c8bfed634cd1a074854db67.png" + }, + { + "username": "neotraxo", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16116966/medium/b30df957873329019a8a90a69f6efe3a.png" + }, + { + "username": "gzxpa", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16123314/medium/487b05577310a946b0b98bc72c11213b_default.png" + }, + { + "username": "TORIK", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16124732/medium/de770890e6411860ac06e8cc2dc0abd0_default.png" + }, + { + "username": "sergio.pibot", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16138114/medium/80db802b2fcd6bbf19ea4c7413367dca.jpeg" + }, + { + "username": "karam-ajaj", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16139838/medium/7539ab958d3c85d5f67e7849483ea8f7.jpeg" + }, + { + "username": "SimonHenz97", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16151520/medium/9b94a85b536688e2d94538c384fd0a76.png" + }, + { + "username": "olsson82", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16198988/medium/eeaab4cba210c537424d4204754b604e.png" + }, + { + "username": "bo3bdo", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16222806/medium/8652f3beacb6098dde5a4cd0a29fe80d.jpeg" + }, + { + "username": "AngryPlayer04", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16245192/medium/342715274f4dc31fd4132cdae9126188.jpeg" + }, + { + "username": "ehatamm", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16245884/medium/979d5e5526fe545be9bf46db481f7182.jpeg" + }, + { + "username": "Balionelis", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16246058/medium/986d62ba363594c517d966fe9178dcbb.png" + }, + { + "username": "kwargs", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16248816/medium/19ce11f04bf1ae2637e0483399c675f9_default.png" + }, + { + "username": "lucicu", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16273892/medium/3b09e8f3bead221ef98d6a45a16851dc_default.png" + }, + { + "username": "Michael5564445", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16357688/medium/9d9026a8bf3eaccb0417da240932ebf7.png" + }, + { + "username": "Netscream", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16359198/medium/694e0c8572dc8a47e6d63da31ec5b992.png" + }, + { + "username": "belicstefan04", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16368142/medium/4742dcfd7bf7ad7e33e37ac44fba7e0f.png" + }, + { + "username": "Hamad2066", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16371478/medium/f37bbc7685b6757defdbd1494236af61.jpeg" + }, + { + "username": "3ct0pl4sm", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16399616/medium/ce796d1c40163975624c0a483e56374f.png" + }, + { + "username": "sanchez.marcell626", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16433865/medium/3ddde1314764cc2205ffdcd1ae719a91.png" + }, + { + "username": "Minoctis", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16490079/medium/91fd0849303a4eca033d660d0a7b6854.jpeg" + }, + { + "username": "homarr", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16657003/medium/3afabfd3de949a54ff5d40ad04552aba.png" + }, + { + "username": "mwgg", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16658379/medium/763dd09f5c238cc5324d4d5357985292.png" + }, + { + "username": "kiwinho", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16671855/medium/bfe3a2d497dc4748a04d02e4ae2139cb.jpeg" + }, + { + "username": "tjvg4m34r13", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16679135/medium/7a483b9b0abe0d925e54808e1cb38fa0.jpeg" + }, + { + "username": "Diegoem", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16705921/medium/29ce68ebc191fc3f65499511b12de98f_default.png" + }, + { + "username": "bouks69", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16746091/medium/b58b1fc08520de416198be9df5d093eb.jpeg" + }, + { + "username": "futhgar", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16748067/medium/b8c526b097f9aa9d687250cac3df16dc.jpeg" + }, + { + "username": "GrimSQL", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16764343/medium/fff729a76d1f8fbcdaee9bb0c0f5f3fd.png" + }, + { + "username": "chnikel", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16767047/medium/3dda2a37e03049dafefe6697bb00f75c.png" + }, + { + "username": "yuki19870616", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16767951/medium/f59c848e38382cda6c8464b0a7b9e642_default.png" + }, + { + "username": "noamdal", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16782245/medium/b4a72a61f9caf138f0322c0cb987e6d0.png" + }, + { + "username": "MalithRukshan", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16809057/medium/084d6a5b35fbbeacc70e7021197d222f.png" + }, + { + "username": "minirope19", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16930929/medium/e8cbbc26747e31c5a8959215e1dd067b.jpeg" + }, + { + "username": "prubin", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17503492/medium/96ac87644691e49c1f983f2f094e541c_default.png" + }, + { + "username": "sam-tam-sam", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17578052/medium/1628dc2954ce3ae95e0caaa2bd60ab0c.png" + }, + { + "username": "toineenzo", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/12371852/medium/9f1b2bedb4794c59479cd289bdba9fab.png" + }, + { + "username": "ArcaneWater", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/12421105/medium/1ac82517a6c658f6b62c48aebcb17e86_default.png" + }, + { + "username": "Ebedami", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/12974801/medium/b596dea5c09454c4c828eac558389755.jpg" + }, + { + "username": "perrygamerptyt", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13117177/medium/1406c949507ecd438480473c8a1f6124.jpg" + }, + { + "username": "SergiSvK", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13320543/medium/3df3c79cc5f0c53716c559cd3fd2fc20.png" + }, + { + "username": "jeongeon", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13362856/medium/eb572f72cde5e5526c517ca3a6489850_default.png" + }, + { + "username": "MrTranCFCVN", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13439475/medium/a1789d69c85d90c667194b5d6a518c08_default.png" + }, + { + "username": "Tobost06", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13467449/medium/9227dc07f6366bc060d28304f5cb8ce7.jpeg" + }, + { + "username": "Kf637", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13530622/medium/118b00bb72d01d3229c97409637e25d1_default.png" + }, + { + "username": "Cruellest", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/13610615/medium/2a74faa0947ee08d18f7946fb8602c1e.jpg" + }, + { + "username": "olavinto", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14424644/medium/37c01732bd2b7a272b421807a05ccfeb.png" + }, + { + "username": "Thario", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14491372/medium/dd5e142070802a672900121aa3f332a6_default.png" + }, + { + "username": "Wjouter", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14585620/medium/b91a51513332bdc0a0a9ecbed99ecbc3.png" + }, + { + "username": "albanobattistella", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14686194/medium/564afcfd76f5cd24751bd669cf4943aa.jpg" + }, + { + "username": "Kachelkaiser", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14763406/medium/203a781797da4a18fe0f4e7db8fd547c.png" + }, + { + "username": "regi4", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14842936/medium/f7e1d672f562a7db61ba6b4b8f4de41d.png" + }, + { + "username": "baton5129", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/14891064/medium/8d438f557b82977dd02f0ead3187265f.PNG" + }, + { + "username": "meviper", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/15958903/medium/209f521ce33a05831fa8d7d1b7babc20_default.png" + }, + { + "username": "GerOriki", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16268376/medium/da00e54b08cd40348231d92873a0cd0a_default.png" + }, + { + "username": "TheRedCyclops", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16486399/medium/7f39226180120d5a9efcb8e13d8aec8e_default.png" + }, + { + "username": "dymek37", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16659221/medium/d1dc6d11d7e7fc370efc5070e837ae03.png" + }, + { + "username": "B3CKDOOR", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16744975/medium/e6c7b2d45e76465d54e6efb67c83da7d.png" + }, + { + "username": "Larsluph", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16779933/medium/ed7d36f8b44013bad3a16ac0491bd0f7.png" + }, + { + "username": "FOEDI", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16781001/medium/6b4552fb72e359aa016f7a054078fac8.png" + }, + { + "username": "xmarkurion", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16805443/medium/34a20428427de5aaef99c7d140646803.png" + }, + { + "username": "gregid", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16806705/medium/f3c8f4a20436e8538929130142bbc104.png" + }, + { + "username": "Flameberg", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16820453/medium/d47be866148474c9d05fec6fbe406d88.png" + }, + { + "username": "Playfust", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16872865/medium/5f4609cc711e5fb9fa8a0b178635769c.jpeg" + }, + { + "username": "Cotignac", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16879297/medium/81ff353edf030699a159bb79cda26e84.jpg" + }, + { + "username": "LeaHun", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16916375/medium/618520f0543b1e212ebc83d66b683d4b_default.png" + }, + { + "username": "jackwellerreal", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16919717/medium/37bbfdc03893f141133ccc619593266d.png" + }, + { + "username": "renan.costaalencar", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16938427/medium/6d25b25320c5bde734118dec4af9cd5b.png" + }, + { + "username": "andrius.cim", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/16967845/medium/46028fc1a0ddfaaeebcb37b39739625d_default.png" + }, + { + "username": "xjxexrxrxyx", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17041412/medium/d34d664166db6fb25579bca9ff3b50b4.jpeg" + }, + { + "username": "bilhal.fellah", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17044572/medium/d1ec6f17e4aa013e9eededc83778d2c6.png" + }, + { + "username": "the_octo", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17058060/medium/7423ab3a4cabb67f5decb2e2dfa2b675_default.png" + }, + { + "username": "BamesJond", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17075846/medium/128d7ffd40254c8e376f45678e2fc620_default.png" + }, + { + "username": "Kornikus", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17134240/medium/d7a42b2c30db46ff152699ca01f9e11a_default.png" + }, + { + "username": "xoxyuxu", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17176526/medium/108055aa24343043de852e412bec74be.png" + }, + { + "username": "cryptodntsleep", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17249408/medium/b9e15aa2b24a0dbc1e4f194aa8ed5109.png" + }, + { + "username": "yaniorg", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17261842/medium/7dbfc77f21c826845961243c44540d26.jpg" + }, + { + "username": "Vidariondr", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17262438/medium/45fbc71be02ef27296b6f423e97b6a03_default.png" + }, + { + "username": "Fastery", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17263066/medium/701b0edc59676174863ad651528bbb37.jpeg" + }, + { + "username": "stratself", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17290388/medium/57d9d8161b3fd0abf4dc5558b4a1fa05_default.png" + }, + { + "username": "wuzeqin", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17292606/medium/b9e0308410b31337e2d7aa6ed346d718_default.png" + }, + { + "username": "ChristopherBull", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17304338/medium/21a175ce596bfae81430767467908b90.jpeg" + }, + { + "username": "darkbcnlord", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17311436/medium/b271bc0b419ec3a26ddb7b63ff8ffc4b.png" + }, + { + "username": "zhoran1997", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17344028/medium/c8f450b5a8f1e9494a45dc60af7ce63e.png" + }, + { + "username": "gilalves1703", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17447768/medium/3f1de562a5c2391c88bbf8d5cf40a266.png" + }, + { + "username": "iServeCloud", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17470960/medium/11649b99d609438d66455a4d2fdc70f7.png" + }, + { + "username": "guibolzantvbox", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17474136/medium/59a576e6da538664ceb972253916fa02.jpeg" + }, + { + "username": "ivann136", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17506062/medium/67d09ada36fac5f444a1f7517e3a97bd_default.png" + }, + { + "username": "Maheshivara", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17516082/medium/576e1e6581cf969615b265de6aeff8b7.jpeg" + }, + { + "username": "brunogui81", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17517542/medium/7c0d174e810435af518fe8e0c05e151f.jpeg" + }, + { + "username": "michelwilhelm", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17542190/medium/4c6b33fd8993ff565fa75add2ce8355e.jpeg" + }, + { + "username": "dias-gxstavo", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17547376/medium/8c6b109aae8aeb651192346a39ae9e5b.jpeg" + }, + { + "username": "ToxykAuBleu", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17614030/medium/8d21e0608560172b121bd46126d827c7.jpeg" + }, + { + "username": "e.erdemir", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17617994/medium/7259a29db9941c6171a8cbbd643b92bd.png" + }, + { + "username": "sjonkreutz", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17618306/medium/7601c45d015189a863656e21348d223b.png" + }, + { + "username": "volovich0377", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17620388/medium/c929a8fbd24f96d17620fa497ade7309.png" + }, + { + "username": "Hamstio1", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17624898/medium/406e0bf40094c24a01c3064f8f5b2a82.png" + }, + { + "username": "i3laa", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17627462/medium/613a9d283ed8b69819ee181903851660.jpeg" + }, + { + "username": "bastiengrignon", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17629884/medium/ddfc3339285bd65195fcd834e512e9b7.jpeg" + }, + { + "username": "kauhee", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17644600/medium/def1b9066cf9275b4273a5a5dca7f325.png" + }, + { + "username": "hongminzheng", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17683860/medium/a764f4963912777d27a7cd98e136a2b2.png" + }, + { + "username": "d-lindahl", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17726729/medium/cbde348582fbabcfadd89a56cd5a0b40.png" + }, + { + "username": "Enoal-Fauchille-Bolle", + "avatarUrl": "https://crowdin-static.cf-downloads.crowdin.com/avatar/17734649/medium/6e6fb29198782dc7856ea21811db669c.jpeg" + } +] diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_board-add-menu.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_board-add-menu.tsx deleted file mode 100644 index c67672fe0..000000000 --- a/apps/nextjs/src/app/[locale]/boards/(content)/_board-add-menu.tsx +++ /dev/null @@ -1,84 +0,0 @@ -"use client"; - -import { useCallback } from "react"; -import { Group, Menu } from "@mantine/core"; -import { IconBox, IconBoxAlignTop, IconChevronDown, IconPlug, IconPlus, IconResize } from "@tabler/icons-react"; - -import { useSession } from "@homarr/auth/client"; -import { useModalAction } from "@homarr/modals"; -import { AppSelectModal } from "@homarr/modals-collection"; -import { useI18n } from "@homarr/translation/client"; - -import { useItemActions } from "~/components/board/items/item-actions"; -import { ItemSelectModal } from "~/components/board/items/item-select-modal"; -import { useCategoryActions } from "~/components/board/sections/category/category-actions"; -import { CategoryEditModal } from "~/components/board/sections/category/category-edit-modal"; -import { useDynamicSectionActions } from "~/components/board/sections/dynamic/dynamic-actions"; -import { IntegrationSelectModal } from "~/components/integration/integration-select-modal"; -import { HeaderButton } from "~/components/layout/header/button"; - -export const BoardAddMenu = () => { - const { data: session } = useSession(); - const { openModal: openCategoryEditModal } = useModalAction(CategoryEditModal); - const { openModal: openItemSelectModal } = useModalAction(ItemSelectModal); - const { openModal: openAppSelectModal } = useModalAction(AppSelectModal); - const { openModal: openIntegrationSelectModal } = useModalAction(IntegrationSelectModal); - const { addCategoryToEnd } = useCategoryActions(); - const { addDynamicSection } = useDynamicSectionActions(); - const { createItem } = useItemActions(); - const t = useI18n(); - - const handleAddCategory = useCallback( - () => - openCategoryEditModal( - { - category: { id: "new", name: "" }, - onSuccess({ name }) { - addCategoryToEnd({ name }); - }, - submitLabel: t("section.category.create.submit"), - }, - { title: (translate) => translate("section.category.create.title") }, - ), - [addCategoryToEnd, openCategoryEditModal, t], - ); - - return ( - - - - - - - - - - - } onClick={() => openItemSelectModal()}> - {t("item.action.create")} - - } - onClick={() => - openAppSelectModal({ - onSelect: (app) => createItem({ kind: "app", options: { appId: app.id } }), - withCreate: session?.user.permissions.includes("app-create") ?? false, - }) - } - > - {t("app.action.add")} - - } onClick={() => openIntegrationSelectModal({})}> - {t("integration.action.create")} - - - } onClick={handleAddCategory}> - {t("section.category.action.create")} - - } onClick={addDynamicSection}> - {t("section.dynamic.action.create")} - - - - ); -}; diff --git a/apps/nextjs/src/app/[locale]/boards/(content)/_edit-actions.tsx b/apps/nextjs/src/app/[locale]/boards/(content)/_edit-actions.tsx index c869e0d62..ca2990680 100644 --- a/apps/nextjs/src/app/[locale]/boards/(content)/_edit-actions.tsx +++ b/apps/nextjs/src/app/[locale]/boards/(content)/_edit-actions.tsx @@ -4,6 +4,7 @@ import { Group, Menu } from "@mantine/core"; import { IconBox, IconChevronDown, IconLayoutGridAdd, IconPlug, IconPlus, IconResize } from "@tabler/icons-react"; import { useSession } from "@homarr/auth/client"; +import { useRequiredBoard } from "@homarr/boards/context"; import { useModalAction } from "@homarr/modals"; import { AppSelectModal } from "@homarr/modals-collection"; import { useI18n } from "@homarr/translation/client"; @@ -20,6 +21,7 @@ export default function BoardEditActions() { const AddMenu = () => { const { data: session } = useSession(); + const board = useRequiredBoard(); const { openModal: openItemSelectModal } = useModalAction(ItemSelectModal); const { openModal: openAppSelectModal } = useModalAction(AppSelectModal); const { openModal: openIntegrationSelectModal } = useModalAction(IntegrationSelectModal); @@ -28,7 +30,7 @@ const AddMenu = () => { const t = useI18n(); const handleSelectItem = () => { - openItemSelectModal(); + openItemSelectModal({ boardId: board.id }); }; const handleSelectApp = () => { diff --git a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_customCss.tsx b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_customCss.tsx index 42e64a3ab..2ad05962c 100644 --- a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_customCss.tsx +++ b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_customCss.tsx @@ -1,6 +1,6 @@ "use client"; -import { Alert, Button, Group, Input, Stack } from "@mantine/core"; +import { Alert, Input } from "@mantine/core"; import { highlight, languages } from "prismjs"; import Editor from "react-simple-code-editor"; @@ -8,65 +8,44 @@ import "~/styles/prismjs.scss"; import { IconInfoCircle } from "@tabler/icons-react"; -import { useForm } from "@homarr/form"; import { useSession } from "@homarr/auth/client"; +import type { UseFormReturnType } from "@homarr/form"; import { useI18n, useScopedI18n } from "@homarr/translation/client"; +import { SectionCard } from "~/components/manage/section-card"; import { WorkshopCssImportButton } from "~/components/workshop/workshop-css-import-button"; - -import type { Board } from "../../_types"; -import { useSavePartialSettingsMutation } from "./_shared"; +import type { FormValues } from "./_settings-form"; import classes from "./customcss.module.css"; interface Props { - board: Board; + form: UseFormReturnType; } -export const CustomCssSettingsContent = ({ board }: Props) => { +export const CustomCssSettingsContent = ({ form }: Props) => { const { data: session } = useSession(); const isAdmin = session?.user.permissions.includes("admin") ?? false; const t = useI18n(); const customCssT = useScopedI18n("board.field.customCss"); - const { mutate: savePartialSettings, isPending } = useSavePartialSettingsMutation(board); - const form = useForm({ - initialValues: { - customCss: board.customCss ?? "", - }, - }); return ( -
    { - savePartialSettings({ - id: board.id, - ...values, - }); - })} - > - - + + - }> - {customCssT("customClassesAlert.description")} - - - - {isAdmin ? form.setFieldValue("customCss", css)} /> : } - - - -
    + }> + {customCssT("customClassesAlert.description")} + + {isAdmin && form.setFieldValue("customCss", css)} />} + ); }; interface CustomCssInputProps { value?: string; onChange: (value: string) => void; + error?: React.ReactNode; } -const CustomCssInput = ({ value, onChange }: CustomCssInputProps) => { +const CustomCssInput = ({ value, onChange, error }: CustomCssInputProps) => { const customCssT = useScopedI18n("board.field.customCss"); return ( @@ -76,6 +55,7 @@ const CustomCssInput = ({ value, onChange }: CustomCssInputProps) => { htmlFor: "custom-css", }} description={customCssT("description")} + error={error} inputWrapperOrder={["label", "description", "input", "error"]} >
    diff --git a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_layout-preview.module.css b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_layout-preview.module.css index 5dab4d40b..f8415e012 100644 --- a/apps/nextjs/src/app/[locale]/boards/[name]/settings/_layout-preview.module.css +++ b/apps/nextjs/src/app/[locale]/boards/[name]/settings/_layout-preview.module.css @@ -59,7 +59,7 @@ } } -.dynamicTile { +.containerTile { border-style: dashed; background: color-mix(in srgb, var(--mantine-color-default) 88%, var(--mantine-primary-color-light)); } diff --git a/apps/nextjs/src/app/[locale]/boards/_layout-utils.spec.ts b/apps/nextjs/src/app/[locale]/boards/_layout-utils.spec.ts index 3124102f5..ff33fa20e 100644 --- a/apps/nextjs/src/app/[locale]/boards/_layout-utils.spec.ts +++ b/apps/nextjs/src/app/[locale]/boards/_layout-utils.spec.ts @@ -1,14 +1,38 @@ import { describe, expect, test } from "vitest"; import { BoardMockBuilder } from "~/components/board/items/actions/test/mocks/board-mock"; -import { DynamicSectionMockBuilder } from "~/components/board/items/actions/test/mocks/dynamic-section-mock"; +import { ContainerSectionMockBuilder } from "~/components/board/items/actions/test/mocks/container-section-mock"; import { EmptySectionMockBuilder } from "~/components/board/items/actions/test/mocks/empty-section-mock"; import { ItemMockBuilder } from "~/components/board/items/actions/test/mocks/item-mock"; import { getRepresentativeLayoutWidth, projectBoardLayout } from "./_layout-utils"; -const mobile = { id: "mobile", name: "Mobile", columnCount: 3, breakpoint: 0, role: "mobile" as const }; -const custom = { id: "tablet", name: "Tablet", columnCount: 6, breakpoint: 480, role: "custom" as const }; -const base = { id: "base", name: "Base", columnCount: 12, breakpoint: 768, role: "base" as const }; +const mobile = { + id: "mobile", + name: "Mobile", + columnCount: 3, + leftGutterColumnCount: 0, + rightGutterColumnCount: 0, + breakpoint: 0, + role: "mobile" as const, +}; +const custom = { + id: "tablet", + name: "Tablet", + columnCount: 6, + leftGutterColumnCount: 0, + rightGutterColumnCount: 0, + breakpoint: 480, + role: "custom" as const, +}; +const base = { + id: "base", + name: "Base", + columnCount: 12, + leftGutterColumnCount: 0, + rightGutterColumnCount: 0, + breakpoint: 768, + role: "base" as const, +}; describe("layout representative widths", () => { test("uses a phone width, activation midpoint, and desktop minimum", () => { @@ -22,30 +46,30 @@ describe("layout representative widths", () => { describe("projectBoardLayout", () => { test("returns exact saved positions without recursively re-projecting the active layout", () => { const rootSection = new EmptySectionMockBuilder({ id: "root" }).build(); - const dynamicSection = new DynamicSectionMockBuilder({ id: "dynamic" }) + const container = new ContainerSectionMockBuilder({ id: "container" }) .addLayout({ layoutId: mobile.id, parentSectionId: rootSection.id, width: 3, height: 2 }) .build(); - const board = new BoardMockBuilder().addLayout(mobile).addSections([rootSection, dynamicSection]).build(); + const board = new BoardMockBuilder().addLayout(mobile).addSections([rootSection, container]).build(); expect(projectBoardLayout(board, mobile, mobile)).toEqual([ - expect.objectContaining({ id: dynamicSection.id, sectionId: rootSection.id, width: 3, height: 2 }), + expect.objectContaining({ id: container.id, sectionId: rootSection.id, width: 3, height: 2 }), ]); }); - test("uses production ordering and sizing for items and dynamic sections", () => { + test("uses production ordering and sizing for items and containers", () => { const rootSection = new EmptySectionMockBuilder({ id: "root" }).build(); - const dynamicSection = new DynamicSectionMockBuilder({ id: "dynamic" }) + const container = new ContainerSectionMockBuilder({ id: "container" }) .addLayout({ layoutId: base.id, parentSectionId: rootSection.id, width: 6, height: 3, xOffset: 6, yOffset: 0 }) .build(); const rootItem = new ItemMockBuilder({ id: "root-item", kind: "clock" }) .addLayout({ layoutId: base.id, sectionId: rootSection.id, width: 5, height: 2, xOffset: 0, yOffset: 0 }) .build(); const nestedItem = new ItemMockBuilder({ id: "nested-item", kind: "clock" }) - .addLayout({ layoutId: base.id, sectionId: dynamicSection.id, width: 4, height: 1, xOffset: 0, yOffset: 0 }) + .addLayout({ layoutId: base.id, sectionId: container.id, width: 4, height: 1, xOffset: 0, yOffset: 0 }) .build(); const board = new BoardMockBuilder() .addLayout(mobile) - .addSections([rootSection, dynamicSection]) + .addSections([rootSection, container]) .addItems([rootItem, nestedItem]) .build(); @@ -59,7 +83,7 @@ describe("projectBoardLayout", () => { yOffset: 0, sectionId: rootSection.id, }); - expect(projected.find((element) => element.id === dynamicSection.id)).toMatchObject({ + expect(projected.find((element) => element.id === container.id)).toMatchObject({ type: "section", width: 3, xOffset: 0, @@ -69,7 +93,7 @@ describe("projectBoardLayout", () => { expect(projected.find((element) => element.id === nestedItem.id)).toMatchObject({ type: "item", width: 3, - sectionId: dynamicSection.id, + sectionId: container.id, }); }); diff --git a/apps/nextjs/src/app/[locale]/boards/_layout-utils.ts b/apps/nextjs/src/app/[locale]/boards/_layout-utils.ts index 46da849d5..8e1d45fe8 100644 --- a/apps/nextjs/src/app/[locale]/boards/_layout-utils.ts +++ b/apps/nextjs/src/app/[locale]/boards/_layout-utils.ts @@ -1,9 +1,12 @@ import { generateResponsiveGridFor } from "@homarr/common"; import type { GridAlgorithmItem } from "@homarr/common"; +import type { BoardLane } from "@homarr/definitions"; +import { boardLanes, getBoardLaneColumnCount, getRootSectionLane } from "@homarr/definitions"; import type { Board } from "./_types"; export type BoardLayout = Board["layouts"][number]; +type LayoutGeometry = Pick; export const getRepresentativeLayoutWidth = (layout: BoardLayout, allLayouts: BoardLayout[]) => { if (layout.role === "mobile") return 390; @@ -17,28 +20,69 @@ export const getRepresentativeLayoutWidth = (layout: BoardLayout, allLayouts: Bo return nextLayout ? Math.round((layout.breakpoint + nextLayout.breakpoint) / 2) : Math.max(1280, layout.breakpoint); }; -export const projectBoardLayout = ( - board: Board, - sourceLayout: Pick, - targetLayout: Pick, -) => { +export const projectBoardLayout = (board: Board, sourceLayout: LayoutGeometry, targetLayout: LayoutGeometry) => { const elements = getElementsForLayout(board, sourceLayout.id); - if (sourceLayout.id === targetLayout.id && sourceLayout.columnCount === targetLayout.columnCount) { + if ( + sourceLayout.id === targetLayout.id && + sourceLayout.columnCount === targetLayout.columnCount && + sourceLayout.leftGutterColumnCount === targetLayout.leftGutterColumnCount && + sourceLayout.rightGutterColumnCount === targetLayout.rightGutterColumnCount + ) { return elements; } - return board.sections - .filter((section) => section.kind !== "dynamic") - .flatMap( - (section) => - generateResponsiveGridFor({ - items: elements, - previousWidth: sourceLayout.columnCount, - width: targetLayout.columnCount, - sectionId: section.id, - }).items, + const emptyRoots = board.sections + .filter((section) => section.kind === "empty") + .toSorted((first, second) => first.xOffset - second.xOffset || first.id.localeCompare(second.id)); + const rootByLane = new Map(); + for (const root of emptyRoots) { + const lane = getRootSectionLane(root.xOffset); + if (!rootByLane.has(lane)) rootByLane.set(lane, root); + } + + const mainRoot = rootByLane.get("main"); + if (!mainRoot) return []; + + const sourceRootById = new Map( + emptyRoots.map((section) => [section.id, getRootSectionLane(section.xOffset)] as const), + ); + const targetLaneBySourceLane = new Map( + boardLanes.map((lane) => [ + lane, + lane !== "main" && getBoardLaneColumnCount(targetLayout, lane) === 0 ? "main" : lane, + ]), + ); + const remappedElements = elements.map((element) => { + const sourceLane = sourceRootById.get(element.sectionId); + if (!sourceLane) return element; + const targetLane = targetLaneBySourceLane.get(sourceLane) ?? "main"; + return { ...element, sectionId: (rootByLane.get(targetLane) ?? mainRoot).id }; + }); + + return boardLanes.flatMap((lane) => { + const root = rootByLane.get(lane); + const width = getBoardLaneColumnCount(targetLayout, lane); + if (!root || width === 0) return []; + + const sourceLanes = boardLanes.filter( + (sourceLane) => + rootByLane.has(sourceLane) && + getBoardLaneColumnCount(sourceLayout, sourceLane) > 0 && + targetLaneBySourceLane.get(sourceLane) === lane, ); + const previousWidth = + sourceLanes.length === 1 + ? getBoardLaneColumnCount(sourceLayout, sourceLanes[0] ?? "main") + : Number.MAX_SAFE_INTEGER; + + return generateResponsiveGridFor({ + items: remappedElements, + previousWidth, + width, + sectionId: root.id, + }).items; + }); }; const getElementsForLayout = (board: Board, layoutId: string): GridAlgorithmItem[] => [ @@ -59,7 +103,7 @@ const getElementsForLayout = (board: Board, layoutId: string): GridAlgorithmItem : []; }), ...board.sections.flatMap((section) => { - if (section.kind !== "dynamic") return []; + if (section.kind !== "container") return []; const layout = section.layouts.find((candidate) => candidate.layoutId === layoutId); return layout?.parentSectionId ? [ diff --git a/apps/nextjs/src/app/[locale]/boards/_providers.tsx b/apps/nextjs/src/app/[locale]/boards/_providers.tsx index cdf917deb..c79644636 100644 --- a/apps/nextjs/src/app/[locale]/boards/_providers.tsx +++ b/apps/nextjs/src/app/[locale]/boards/_providers.tsx @@ -11,10 +11,18 @@ import type { Board } from "./_types"; interface Props { initialBoard: Board; + initialLayoutId: string; + initialViewportWidth: number; canModify: boolean; } -export const BoardProviders = ({ children, initialBoard, canModify }: PropsWithChildren) => { +export const BoardProviders = ({ + children, + initialBoard, + initialLayoutId, + initialViewportWidth, + canModify, +}: PropsWithChildren) => { const searchParams = useSearchParams(); const isDesktop = useMediaQuery("(min-width: 64em)"); const requestedLayoutId = searchParams.get("layout"); @@ -23,7 +31,12 @@ export const BoardProviders = ({ children, initialBoard, canModify }: PropsWithC const layoutOverrideId = isLayoutEditRequest && isDesktop ? requestedLayoutId : null; return ( - + {children} ); diff --git a/apps/nextjs/src/app/[locale]/layout.tsx b/apps/nextjs/src/app/[locale]/layout.tsx index b0d51beb3..b2cb2f731 100644 --- a/apps/nextjs/src/app/[locale]/layout.tsx +++ b/apps/nextjs/src/app/[locale]/layout.tsx @@ -15,9 +15,10 @@ import { NextIntlClientProvider } from "next-intl"; import { api } from "@homarr/api/server"; import { env as authEnv } from "@homarr/auth/env"; +import { getRscServerSettingsAsync } from "@homarr/api/server-settings-server"; +import { getRscUserSettingsAsync } from "@homarr/api/user-server"; import { auth } from "@homarr/auth/next"; -import { db } from "@homarr/db"; -import { getServerSettingsAsync } from "@homarr/db/queries"; +import { createLogger } from "@homarr/core/infrastructure/logs"; import { ModalProvider } from "@homarr/modals"; import { Notifications } from "@homarr/notifications"; import { SettingsProvider } from "@homarr/settings"; @@ -48,6 +49,8 @@ const fontSans = Inter({ variable: "--font-sans", }); +const logger = createLogger({ module: "rootLayout" }); + // eslint-disable-next-line no-restricted-syntax export const generateMetadata = async (): Promise => ({ title: "Homarr", @@ -83,25 +86,36 @@ export default async function Layout(props: { children: React.ReactNode; params: Promise<{ locale: SupportedLanguage }>; }) { - if (!isLocaleSupported((await props.params).locale)) { + const { locale } = await props.params; + if (!isLocaleSupported(locale)) { notFound(); } - const session = await auth(); - const user = session ? await api.user.getById({ userId: session.user.id }).catch(() => null) : null; - const serverSettings = await getServerSettingsAsync(db); - // Resolved on the server so the assistant runtime chunk is never referenced by a page unless the - // assistant is actually usable. Reuses the availability check the management page invalidates. - // The states stay distinct so a signed-out visitor is told to sign in rather than that the - // instance is unconfigured, which the server cannot know for them. - const assistantAvailability: AssistantAvailability = !session - ? "unauthenticated" - : await api.assistant - .getAvailability() - .then((availability) => (availability.enabled ? ("enabled" as const) : ("unconfigured" as const))) - .catch(() => "error" as const); - const colorScheme = await getCurrentColorSchemeAsync(); - const direction = isLocaleRTL((await props.params).locale) ? "rtl" : "ltr"; + const sessionPromise = auth(); + const userPromise = sessionPromise.then((session) => + session + ? getRscUserSettingsAsync(session.user.id).catch((error: unknown) => { + logger.error(new Error("Failed to load the authenticated user in the root layout", { cause: error })); + return null; + }) + : null, + ); + const assistantAvailabilityPromise: Promise = sessionPromise.then((session) => + !session + ? "unauthenticated" + : api.assistant + .getAvailability() + .then((availability) => (availability.enabled ? "enabled" : "unconfigured")) + .catch(() => "error"), + ); + const [session, user, serverSettings, colorScheme, assistantAvailability] = await Promise.all([ + sessionPromise, + userPromise, + getRscServerSettingsAsync(), + getCurrentColorSchemeAsync(), + assistantAvailabilityPromise, + ]); + const direction = isLocaleRTL(locale) ? "rtl" : "ltr"; const publicUrls = resolveHomarrUrlConfig({ homarrWebsiteUrl: env.HOMARR_WEBSITE_URL, workshopApiUrl: env.WORKSHOP_API_URL, @@ -146,8 +160,6 @@ export default async function Layout(props: { (innerProps) => , ]); - const { locale } = await props.params; - return ( // Instead of ColorSchemScript we use data-mantine-color-scheme to prevent flickering { - test("asks Homarr Assistant to create a definition and includes the user's request", () => { - const prompt = buildAiPrompt( - schema, - '{"status":"online"}', - { - $schema: "homarr-custom-widget-v2", - name: "Status", - url: "https://example.com/status", - }, - "Show a compact green status when the service is online.", - ); - - expect(prompt).toContain("`customWidget_create`"); - expect(prompt).toContain("`secrets: []`"); - expect(prompt).toContain("do not ask for typed confirmation"); - expect(prompt).toContain('```json\n{"status":"online"}\n```'); - expect(prompt).toContain('"name": "Status"'); - expect(prompt).toContain("Show a compact green status when the service is online."); - }); - - test("asks Homarr Assistant to update the selected definition without replacing its secrets", () => { - const prompt = buildAiPrompt( - schema, - null, - { - name: "Existing widget", - authType: "bearer", - }, - "Use a progress bar.", - "widget-definition-id", - ); - - expect(prompt).toContain("custom widget definition `widget-definition-id`"); - expect(prompt).toContain("`customWidget_update`"); - expect(prompt).toContain("Preserve configured secrets by omitting the `secrets` field"); - expect(prompt).not.toContain('"secrets"'); - }); - - test("keeps copy-to-clipboard prompts useful before a request is entered", () => { - const prompt = buildAiPrompt(schema); - - expect(prompt).toContain("PASTE_YOUR_API_RESPONSE_HERE"); - expect(prompt).toContain("Describe what you want the widget to show or change here."); - }); -}); diff --git a/apps/nextjs/src/app/[locale]/manage/layout.tsx b/apps/nextjs/src/app/[locale]/manage/layout.tsx index ac3a2355a..7e8a7fff2 100644 --- a/apps/nextjs/src/app/[locale]/manage/layout.tsx +++ b/apps/nextjs/src/app/[locale]/manage/layout.tsx @@ -29,8 +29,10 @@ import { IconUsersGroup, } from "@tabler/icons-react"; +import { getRscUserSettingsAsync } from "@homarr/api/user-server"; import { auth } from "@homarr/auth/next"; import { isProviderEnabled } from "@homarr/auth/server"; +import { createLogger } from "@homarr/core/infrastructure/logs"; import { createDocumentationLink } from "@homarr/definitions"; import { dbEnv } from "@homarr/core/infrastructure/db/env"; import { env } from "@homarr/docker/env"; @@ -41,11 +43,29 @@ import { homarrLogoPath } from "~/components/layout/logo/homarr-logo"; import type { NavigationLink } from "~/components/layout/navigation"; import { MainNavigation } from "~/components/layout/navigation"; import { ClientShell } from "~/components/layout/shell"; -import { ManageTourProvider } from "~/components/onboarding/manage-tour"; +import { ManageTourGate } from "~/components/onboarding/manage-tour-gate"; +import { env as nextEnv } from "~/env"; + +const logger = createLogger({ module: "manageLayout" }); export default async function ManageLayout({ children }: PropsWithChildren) { - const t = await getScopedI18n("management.navbar"); - const session = await auth(); + const sessionPromise = auth(); + const shouldRunManageTourPromise = sessionPromise.then(async (session) => { + if (!session || nextEnv.DEMO_MODE) return false; + + try { + const user = await getRscUserSettingsAsync(session.user.id); + return user !== undefined && !user.completedManageTour; + } catch (error) { + logger.error(new Error("Failed to load the management tour status", { cause: error })); + return false; + } + }); + const [t, session, shouldRunManageTour] = await Promise.all([ + getScopedI18n("management.navbar"), + sessionPromise, + shouldRunManageTourPromise, + ]); const navigationLinks: NavigationLink[] = [ { label: t("items.home"), @@ -63,7 +83,7 @@ export default async function ManageLayout({ children }: PropsWithChildren) { icon: IconBox, href: "/manage/apps", label: t("items.apps"), - hidden: !session, + hidden: !session?.user.permissions.includes("app-create"), iconProps: { strokeWidth: 2.5, }, @@ -73,7 +93,7 @@ export default async function ManageLayout({ children }: PropsWithChildren) { icon: IconAffiliateFilled, href: "/manage/integrations", label: t("items.integrations"), - hidden: !session, + hidden: !session?.user.permissions.includes("integration-create"), "data-onboarding-tour-id": "manage-integrations", }, { @@ -92,7 +112,7 @@ export default async function ManageLayout({ children }: PropsWithChildren) { icon: IconSearch, href: "/manage/search-engines", label: t("items.searchEngies"), - hidden: !session, + hidden: !session?.user.permissions.includes("search-engine-create"), iconProps: { strokeWidth: 2.5, }, @@ -102,7 +122,7 @@ export default async function ManageLayout({ children }: PropsWithChildren) { icon: IconPhotoFilled, href: "/manage/medias", label: t("items.medias"), - hidden: !session, + hidden: !session?.user.permissions.includes("media-upload"), "data-onboarding-tour-id": "manage-medias", }, { @@ -239,7 +259,9 @@ export default async function ManageLayout({ children }: PropsWithChildren) { ); - if (!session) return shell; - - return {shell}; + return ( + + {shell} + + ); } diff --git a/apps/nextjs/src/components/assistant/assistant-widget-tool.tsx b/apps/nextjs/src/components/assistant/assistant-widget-tool.tsx index 02bd5aa64..1ad4552d2 100644 --- a/apps/nextjs/src/components/assistant/assistant-widget-tool.tsx +++ b/apps/nextjs/src/components/assistant/assistant-widget-tool.tsx @@ -213,6 +213,7 @@ export const AssistantConfigureWidgetTool = ({ openModal( { kind: args.kind, + definition: widgetImports[args.kind].definition, value: configuration.value, integrationData: configuration.integrationData, integrationSupport: configuration.integrationSupport, diff --git a/apps/nextjs/src/components/board/advanced-focus/manual-surface.spec.ts b/apps/nextjs/src/components/board/advanced-focus/manual-surface.spec.ts index 3d5827aef..b659efc9c 100644 --- a/apps/nextjs/src/components/board/advanced-focus/manual-surface.spec.ts +++ b/apps/nextjs/src/components/board/advanced-focus/manual-surface.spec.ts @@ -83,7 +83,7 @@ describe("AdvancedFocusManualSurface", () => { expect(dialog?.id).toBe("advanced-focus-test"); expect(dialog?.getAttribute("aria-modal")).toBe("true"); expect(dialog?.closest("[data-portal]")).not.toBeNull(); - expect(dialog?.closest(".grid-stack-item")).toBeNull(); + expect(dialog?.closest("[data-grid-item-id]")).toBeNull(); expect(document.getElementById(dialog?.getAttribute("aria-labelledby") ?? "")?.textContent).toBe( "Test widget advanced view", ); diff --git a/apps/nextjs/src/components/board/items/actions/empty-position.ts b/apps/nextjs/src/components/board/items/actions/empty-position.ts index 836b412cc..2f3875627 100644 --- a/apps/nextjs/src/components/board/items/actions/empty-position.ts +++ b/apps/nextjs/src/components/board/items/actions/empty-position.ts @@ -7,7 +7,7 @@ export const getFirstEmptyPosition = ( size: { width: number; height: number } = { width: 1, height: 1 }, ) => { for (let yOffset = 0; yOffset < rowCount + 1 - size.height; yOffset++) { - for (let xOffset = 0; xOffset <= columnCount - size.width; xOffset++) { + for (let xOffset = 0; xOffset < columnCount + 1 - size.width; xOffset++) { const isOccupied = elements.some( (element) => element.yOffset < yOffset + size.height && diff --git a/apps/nextjs/src/components/board/items/lazy-item-move-modal.tsx b/apps/nextjs/src/components/board/items/lazy-item-move-modal.tsx deleted file mode 100644 index 836017bc1..000000000 --- a/apps/nextjs/src/components/board/items/lazy-item-move-modal.tsx +++ /dev/null @@ -1,67 +0,0 @@ -"use client"; - -import { Suspense, use } from "react"; -import { Center, Loader } from "@mantine/core"; -import { ErrorBoundary } from "react-error-boundary"; - -import { createModal, modalSizeForm } from "@homarr/modals"; -import { WidgetError } from "@homarr/widgets/errors"; - -import type { ItemMoveModalProps } from "./item-move-modal"; - -let itemMoveModalPromise: Promise | undefined; - -const loadItemMoveModal = () => { - if (itemMoveModalPromise) return itemMoveModalPromise; - - const currentPromise = import("./item-move-modal"); - itemMoveModalPromise = currentPromise; - void currentPromise.catch(() => { - if (itemMoveModalPromise === currentPromise) itemMoveModalPromise = undefined; - }); - return currentPromise; -}; - -export const preloadItemMoveModal = () => void loadItemMoveModal().catch(() => undefined); - -interface LazyItemMoveModalContentProps { - actions: { closeModal: () => void }; - innerProps: ItemMoveModalProps; -} - -const LazyItemMoveModalContent = (props: LazyItemMoveModalContentProps) => { - const { ItemMoveModal } = use(loadItemMoveModal()); - const Component = ItemMoveModal.component; - return ; -}; - -export const LazyItemMoveModal = createModal((props) => ( - ( -
    - { - itemMoveModalPromise = undefined; - resetErrorBoundary(); - }} - /> -
    - )} - > - - - - } - > - - -
    -)).withOptions({ - defaultTitle(t) { - return t("item.moveResize.title"); - }, - size: modalSizeForm, -}); diff --git a/apps/nextjs/src/components/board/items/widget-query-recovery.ts b/apps/nextjs/src/components/board/items/widget-query-recovery.ts index 9bb0b81c5..ba80f3ee2 100644 --- a/apps/nextjs/src/components/board/items/widget-query-recovery.ts +++ b/apps/nextjs/src/components/board/items/widget-query-recovery.ts @@ -1,5 +1,5 @@ import type { QueryClient, QueryKey } from "@tanstack/react-query"; -export const removeWidgetDataQueries = (queryClient: QueryClient, queryKeys: QueryKey[]) => { +export const removeWidgetDataQueries = (queryClient: QueryClient, queryKeys: readonly QueryKey[]) => { queryKeys.forEach((queryKey) => queryClient.removeQueries({ queryKey })); }; diff --git a/apps/nextjs/src/components/board/items/widget-query-scope.spec.ts b/apps/nextjs/src/components/board/items/widget-query-scope.spec.ts index e11e21086..ec667102e 100644 --- a/apps/nextjs/src/components/board/items/widget-query-scope.spec.ts +++ b/apps/nextjs/src/components/board/items/widget-query-scope.spec.ts @@ -172,7 +172,7 @@ describe("matchesWidgetItemQuery", () => { integrationIds: ["beszel-1"], systemId: "system-1", timePeriod: "1h", - includeDocker: false, + includeDocker: true, }, }; const scope = createScope({ integrationIds: ["beszel-1"], runtimeQueries: [activeQuery] }); diff --git a/apps/nextjs/src/components/board/layout/test/board-lanes.spec.ts b/apps/nextjs/src/components/board/layout/test/board-lanes.spec.ts index 72a8bc3f4..83058fd89 100644 --- a/apps/nextjs/src/components/board/layout/test/board-lanes.spec.ts +++ b/apps/nextjs/src/components/board/layout/test/board-lanes.spec.ts @@ -16,6 +16,7 @@ describe("board lanes", () => { leftGutterColumnCount: 2, rightGutterColumnCount: 3, breakpoint: 0, + role: "base", } satisfies Board["layouts"][number]; expect(getBoardLaneColumnCount(layout, "left")).toBe(2); @@ -31,6 +32,7 @@ describe("board lanes", () => { leftGutterColumnCount: 3, rightGutterColumnCount: 3, breakpoint: 0, + role: "base", } satisfies Board["layouts"][number]; expect(getBoardLaneColumnCount(layout, "left")).toBe(3); @@ -120,6 +122,7 @@ describe("board lanes", () => { leftGutterColumnCount: 1, rightGutterColumnCount: 0, breakpoint: 0, + role: "base", }, ]; diff --git a/apps/nextjs/src/components/board/sections/grid/grid-portal-host.tsx b/apps/nextjs/src/components/board/sections/grid/grid-portal-host.tsx index 5e5e9a297..f08afa600 100644 --- a/apps/nextjs/src/components/board/sections/grid/grid-portal-host.tsx +++ b/apps/nextjs/src/components/board/sections/grid/grid-portal-host.tsx @@ -5,8 +5,10 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, use import { createPortal } from "react-dom"; import type { RouterOutputs } from "@homarr/api"; -import { useIntegrations } from "@homarr/auth/client"; +import { clientApi } from "@homarr/api/client"; +import { useSession } from "@homarr/auth/client"; import { useCurrentLayout, useRequiredBoard } from "@homarr/boards/context"; +import { useEditMode } from "@homarr/boards/edit-mode"; import { getRootSectionLane } from "@homarr/definitions"; import type { ContainerSectionItem, Section } from "~/app/[locale]/boards/_types"; @@ -33,7 +35,11 @@ const GridPortalHostContext = createContext(n */ export const BoardGridPortalHost = ({ children }: PropsWithChildren) => { const board = useRequiredBoard(); - const integrations = useIntegrations(); + const { data: session } = useSession(); + const [isEditMode] = useEditMode(); + const { data: integrations } = clientApi.integration.all.useQuery(undefined, { + enabled: Boolean(session) && isEditMode, + }); const containersRef = useRef>(new Map()); const [containers, setContainers] = useState>(() => new Map()); const [announcement, setAnnouncement] = useState({ id: 0, message: "" }); diff --git a/apps/nextjs/src/components/board/sections/grid/test/grid-portal-host.spec.ts b/apps/nextjs/src/components/board/sections/grid/test/grid-portal-host.spec.ts index f5b95d969..d38ea78de 100644 --- a/apps/nextjs/src/components/board/sections/grid/test/grid-portal-host.spec.ts +++ b/apps/nextjs/src/components/board/sections/grid/test/grid-portal-host.spec.ts @@ -12,8 +12,18 @@ const mocks = vi.hoisted(() => ({ }, })); +vi.mock("@homarr/api/client", () => ({ + clientApi: { + integration: { + all: { + useQuery: () => ({ data: undefined }), + }, + }, + }, +})); + vi.mock("@homarr/auth/client", () => ({ - useIntegrations: () => undefined, + useSession: () => ({ data: { user: { id: "user" } } }), })); vi.mock("@homarr/boards/context", () => ({ @@ -21,6 +31,10 @@ vi.mock("@homarr/boards/context", () => ({ useRequiredBoard: () => mocks.board, })); +vi.mock("@homarr/boards/edit-mode", () => ({ + useEditMode: () => [true], +})); + describe("board grid portal host", () => { let container: HTMLDivElement; let root: Root; diff --git a/apps/nextjs/src/components/board/sections/gridstack/board-empty-space-context-menu.module.css b/apps/nextjs/src/components/board/sections/gridstack/board-empty-space-context-menu.module.css deleted file mode 100644 index fe141c3f7..000000000 --- a/apps/nextjs/src/components/board/sections/gridstack/board-empty-space-context-menu.module.css +++ /dev/null @@ -1,4 +0,0 @@ -.suppressTouchCallout { - user-select: none; - -webkit-touch-callout: none; -} diff --git a/apps/nextjs/src/components/board/sections/gridstack/board-empty-space-context-menu.tsx b/apps/nextjs/src/components/board/sections/gridstack/board-empty-space-context-menu.tsx deleted file mode 100644 index ac1673369..000000000 --- a/apps/nextjs/src/components/board/sections/gridstack/board-empty-space-context-menu.tsx +++ /dev/null @@ -1,226 +0,0 @@ -"use client"; - -import type { KeyboardEvent, MouseEvent, PointerEvent, PropsWithChildren } from "react"; -import { useEffect, useRef, useState } from "react"; -import type { BoxProps } from "@mantine/core"; -import { Box, Menu } from "@mantine/core"; -import { IconPlus } from "@tabler/icons-react"; - -import { useCurrentLayout, useRequiredBoard } from "@homarr/boards/context"; -import { useEditMode } from "@homarr/boards/edit-mode"; -import { useModalAction } from "@homarr/modals"; -import { useSettings } from "@homarr/settings"; -import { useI18n } from "@homarr/translation/client"; - -import type { DynamicSectionItem, Section } from "~/app/[locale]/boards/_types"; -import { ItemSelectModal } from "../../items/item-select-modal"; -import { useBoardPermissions } from "../../permissions/client"; -import type { BoardPlacementHint } from "../../items/actions/create-item"; -import type { UseGridstackRefs } from "./use-gridstack"; -import classes from "./board-empty-space-context-menu.module.css"; -import { hasExceededLongPressMoveTolerance } from "./long-press"; - -const suppressTouchCalloutClass = classes.suppressTouchCallout as string; - -interface MenuState { - x: number; - y: number; - placement: BoardPlacementHint; -} - -interface Props extends BoxProps { - section: Exclude | DynamicSectionItem; - refs: UseGridstackRefs; -} - -export const BoardEmptySpaceContextMenu = ({ section, refs, children, ...boxProps }: PropsWithChildren) => { - const board = useRequiredBoard(); - const currentLayoutId = useCurrentLayout(); - const settings = useSettings(); - const t = useI18n(); - const { hasChangeAccess } = useBoardPermissions(board); - const { openModal } = useModalAction(ItemSelectModal); - const [isEditMode] = useEditMode(); - const [menu, setMenu] = useState(null); - const longPressTimer = useRef | null>(null); - const longPressPointer = useRef<{ pointerId: number; x: number; y: number } | null>(null); - const touchGuardElement = useRef(null); - const returnFocusRef = useRef(null); - - const enabled = hasChangeAccess && settings.enableRightClickOnWidgets; - const closeMenu = (afterFocusRestore?: (returnFocus: HTMLElement | null) => void) => { - const returnFocus = returnFocusRef.current; - returnFocusRef.current = null; - setMenu(null); - requestAnimationFrame(() => { - returnFocus?.focus(); - afterFocusRestore?.(returnFocus); - }); - }; - const clearLongPress = () => { - if (longPressTimer.current !== null) { - clearTimeout(longPressTimer.current); - longPressTimer.current = null; - } - touchGuardElement.current?.classList.remove(suppressTouchCalloutClass); - touchGuardElement.current = null; - longPressPointer.current = null; - }; - - useEffect( - () => () => { - if (longPressTimer.current !== null) clearTimeout(longPressTimer.current); - touchGuardElement.current?.classList.remove(suppressTouchCalloutClass); - }, - [], - ); - const resolvePlacement = (target: EventTarget | null, pageX: number, pageY: number) => { - const wrapper = refs.wrapperElement.current; - const gridstack = refs.gridstack.current; - if (!(target instanceof Element) || !wrapper || !gridstack) return null; - if (target.closest(".grid-stack") !== wrapper || target.closest(".grid-stack-item")) return null; - - const cell = gridstack.getCellFromPixel({ left: pageX, top: pageY }, true); - const rowLimit = section.kind === "dynamic" ? section.height : undefined; - if ( - cell.x < 0 || - cell.y < 0 || - cell.x >= gridstack.getColumn() || - (rowLimit !== undefined && cell.y >= rowLimit) || - !gridstack.isAreaEmpty(cell.x, cell.y, 1, 1) - ) { - return null; - } - - return { sectionId: section.id, layoutId: currentLayoutId, xOffset: cell.x, yOffset: cell.y }; - }; - - const handleContextMenu = (event: MouseEvent) => { - if (!enabled) return; - const placement = resolvePlacement(event.target, event.pageX, event.pageY); - if (!placement) return; - event.preventDefault(); - event.stopPropagation(); - returnFocusRef.current = event.currentTarget; - setMenu({ x: event.clientX, y: event.clientY, placement }); - }; - - const handlePointerDown = (event: PointerEvent) => { - if (!enabled || event.pointerType !== "touch") return; - const placement = resolvePlacement(event.target, event.pageX, event.pageY); - if (!placement) return; - const returnFocus = event.currentTarget; - clearLongPress(); - longPressPointer.current = { pointerId: event.pointerId, x: event.clientX, y: event.clientY }; - touchGuardElement.current = event.currentTarget; - touchGuardElement.current.classList.add(suppressTouchCalloutClass); - longPressTimer.current = setTimeout(() => { - returnFocusRef.current = returnFocus; - setMenu({ x: event.clientX, y: event.clientY, placement }); - navigator.vibrate?.(20); - }, 500); - }; - - const handlePointerMove = (event: PointerEvent) => { - const pointer = longPressPointer.current; - if ( - !pointer || - pointer.pointerId !== event.pointerId || - !hasExceededLongPressMoveTolerance(pointer, { x: event.clientX, y: event.clientY }) - ) { - return; - } - clearLongPress(); - }; - - const handlePointerEnd = (event: PointerEvent) => { - if (longPressPointer.current?.pointerId === event.pointerId) clearLongPress(); - }; - - const handleKeyDown = (event: KeyboardEvent) => { - if ( - !enabled || - event.currentTarget !== event.target || - (event.key !== "ContextMenu" && !(event.shiftKey && event.key === "F10")) - ) { - return; - } - const wrapper = event.currentTarget; - const gridstack = refs.gridstack.current; - if (!gridstack) return; - - const rowCount = Math.max(1, section.kind === "dynamic" ? section.height : gridstack.getRow() + 1); - for (let yOffset = 0; yOffset < rowCount; yOffset++) { - for (let xOffset = 0; xOffset < gridstack.getColumn(); xOffset++) { - if (!gridstack.isAreaEmpty(xOffset, yOffset, 1, 1)) continue; - const rect = wrapper.getBoundingClientRect(); - event.preventDefault(); - returnFocusRef.current = wrapper; - setMenu({ - x: rect.left + 24, - y: rect.top + 24, - placement: { sectionId: section.id, layoutId: currentLayoutId, xOffset, yOffset }, - }); - return; - } - } - }; - - return ( - <> - - {children} - - { - if (!opened) closeMenu(); - }} - withinPortal - position="bottom-start" - returnFocus={false} - > - - - - - } - onClick={() => { - const placement = menu?.placement; - closeMenu((returnFocus) => { - if (!placement) return; - openModal( - { placement, board, persistImmediately: !isEditMode }, - { - onClose: () => { - requestAnimationFrame(() => { - if (returnFocus?.isConnected) returnFocus.focus(); - }); - }, - }, - ); - }); - }} - > - {t("item.create.addAtPosition")} - - - - - ); -}; diff --git a/apps/nextjs/src/components/board/sections/gridstack/gridstack.spec.ts b/apps/nextjs/src/components/board/sections/gridstack/gridstack.spec.ts deleted file mode 100644 index 3df5c1a38..000000000 --- a/apps/nextjs/src/components/board/sections/gridstack/gridstack.spec.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { describe, expect, test } from "vitest"; - -import { filterRecursiveInnerSections } from "./gridstack"; - -describe("filterRecursiveInnerSections", () => { - test("removes sections that would recursively render an ancestor", () => { - const innerSections = [{ id: "safe" }, { id: "parent" }, { id: "root" }]; - - expect(filterRecursiveInnerSections(innerSections, new Set(["root", "parent"]))).toEqual([{ id: "safe" }]); - }); -}); diff --git a/apps/nextjs/src/components/board/sections/gridstack/long-press.spec.ts b/apps/nextjs/src/components/board/sections/gridstack/long-press.spec.ts deleted file mode 100644 index 9ab4461e3..000000000 --- a/apps/nextjs/src/components/board/sections/gridstack/long-press.spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { describe, expect, test } from "vitest"; - -import { hasExceededLongPressMoveTolerance } from "./long-press"; - -describe("hasExceededLongPressMoveTolerance", () => { - test("allows small touch jitter", () => { - expect(hasExceededLongPressMoveTolerance({ x: 100, y: 100 }, { x: 106, y: 106 })).toBe(false); - }); - - test("allows movement exactly at the threshold", () => { - expect(hasExceededLongPressMoveTolerance({ x: 100, y: 100 }, { x: 106, y: 108 })).toBe(false); - }); - - test("cancels a deliberate scroll gesture", () => { - expect(hasExceededLongPressMoveTolerance({ x: 100, y: 100 }, { x: 100, y: 116 })).toBe(true); - }); -}); diff --git a/apps/nextjs/src/components/board/sections/gridstack/long-press.ts b/apps/nextjs/src/components/board/sections/gridstack/long-press.ts deleted file mode 100644 index d7b94ad01..000000000 --- a/apps/nextjs/src/components/board/sections/gridstack/long-press.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const longPressMoveTolerancePx = 10; - -export const hasExceededLongPressMoveTolerance = ( - start: { x: number; y: number }, - current: { x: number; y: number }, - tolerance = longPressMoveTolerancePx, -) => Math.hypot(current.x - start.x, current.y - start.y) > tolerance; diff --git a/apps/nextjs/src/components/board/sections/section-actions.spec.ts b/apps/nextjs/src/components/board/sections/section-actions.spec.ts index 32c413f97..441e71ef7 100644 --- a/apps/nextjs/src/components/board/sections/section-actions.spec.ts +++ b/apps/nextjs/src/components/board/sections/section-actions.spec.ts @@ -1,18 +1,18 @@ import { describe, expect, test } from "vitest"; import { BoardMockBuilder } from "~/components/board/items/actions/test/mocks/board-mock"; -import { DynamicSectionMockBuilder } from "~/components/board/items/actions/test/mocks/dynamic-section-mock"; +import { ContainerSectionMockBuilder } from "~/components/board/items/actions/test/mocks/container-section-mock"; import { EmptySectionMockBuilder } from "~/components/board/items/actions/test/mocks/empty-section-mock"; import { wouldCreateSectionCycle } from "./section-actions"; describe("wouldCreateSectionCycle", () => { - test("rejects moving a dynamic section into itself or one of its descendants", () => { + test("rejects moving a container into itself or one of its descendants", () => { const layoutId = "layout"; const rootSection = new EmptySectionMockBuilder({ id: "root" }).build(); - const parentSection = new DynamicSectionMockBuilder({ id: "parent" }) + const parentSection = new ContainerSectionMockBuilder({ id: "parent" }) .addLayout({ layoutId, parentSectionId: rootSection.id }) .build(); - const childSection = new DynamicSectionMockBuilder({ id: "child" }) + const childSection = new ContainerSectionMockBuilder({ id: "child" }) .addLayout({ layoutId, parentSectionId: parentSection.id }) .build(); const board = new BoardMockBuilder().addSections([rootSection, parentSection, childSection]).build(); diff --git a/apps/nextjs/src/components/board/sections/section-actions.tsx b/apps/nextjs/src/components/board/sections/section-actions.tsx index f2cdac751..47813fc16 100644 --- a/apps/nextjs/src/components/board/sections/section-actions.tsx +++ b/apps/nextjs/src/components/board/sections/section-actions.tsx @@ -101,7 +101,7 @@ export const wouldCreateSectionCycle = ( visitedSectionIds.add(currentSectionId); const currentSection = board.sections.find((section) => section.id === currentSectionId); - if (currentSection?.kind !== "dynamic") return false; + if (currentSection?.kind !== "container") return false; currentSectionId = currentSection.layouts.find((layout) => layout.layoutId === layoutId)?.parentSectionId ?? null; } diff --git a/apps/nextjs/src/components/board/sections/use-open-section-apps.ts b/apps/nextjs/src/components/board/sections/use-open-section-apps.ts index cc2e7ab43..d462fdda9 100644 --- a/apps/nextjs/src/components/board/sections/use-open-section-apps.ts +++ b/apps/nextjs/src/components/board/sections/use-open-section-apps.ts @@ -1,4 +1,4 @@ -import { useCallback, useMemo } from "react"; +import { use, useCallback, useMemo } from "react"; import { clientApi } from "@homarr/api/client"; import { useCurrentLayout, useRequiredBoard } from "@homarr/boards/context"; @@ -6,9 +6,10 @@ import { getSafeAppHref } from "@homarr/common"; import { useConfirmModal } from "@homarr/modals"; import { useSettings } from "@homarr/settings"; import { useI18n } from "@homarr/translation/client"; +import type { WidgetComponentProps } from "@homarr/widgets/definition"; +import { loadWidgetDefinition, reduceWidgetOptionsWithDefinition } from "@homarr/widgets/manifest"; import type { Item } from "~/app/[locale]/boards/_types"; -import { filterByItemKind } from "./filter-by-item-kind"; interface SectionItemLayout { layoutId: string; @@ -80,10 +81,27 @@ export const useOpenSectionApps = (sectionId: string, enabled: boolean) => { const settings = useSettings(); const { openConfirmModal } = useConfirmModal(); const t = useI18n(); + const appDefinition = use(loadWidgetDefinition("app")); const appIds = useMemo(() => { const items: Item[] = getSectionItemsForLayout(board, sectionId, currentLayoutId); - return Array.from(new Set(filterByItemKind(items, settings, "app").map((item) => item.options.appId))); - }, [board, currentLayoutId, sectionId, settings]); + return Array.from( + new Set( + items + .filter((item) => item.kind === "app") + .map( + (item) => + ( + reduceWidgetOptionsWithDefinition( + appDefinition, + settings, + item.options, + ) as WidgetComponentProps<"app">["options"] + ).appId, + ) + .filter((appId): appId is string => typeof appId === "string"), + ), + ); + }, [appDefinition, board, currentLayoutId, sectionId, settings]); const { data: apps = [], isLoading } = clientApi.app.byIds.useQuery(appIds, { enabled: enabled && appIds.length > 0, staleTime: 30_000, diff --git a/apps/nextjs/src/components/onboarding/board-tour-gate.tsx b/apps/nextjs/src/components/onboarding/board-tour-gate.tsx index 31365544f..454d20fa2 100644 --- a/apps/nextjs/src/components/onboarding/board-tour-gate.tsx +++ b/apps/nextjs/src/components/onboarding/board-tour-gate.tsx @@ -5,7 +5,7 @@ export const BoardTourGate = async ({ enabled, children }: PropsWithChildren<{ e // Native server-side import keeps the completed-user client graph lean while // giving first-time users one stable board tree instead of swapping a - // Suspense fallback after GridStack has mounted. + // Suspense fallback after the board grid has mounted. const { BoardTourProvider } = await import("./board-tour"); return {children}; }; diff --git a/apps/nextjs/src/components/user-avatar-menu.tsx b/apps/nextjs/src/components/user-avatar-menu.tsx index 4b01f96ca..ea6109b73 100644 --- a/apps/nextjs/src/components/user-avatar-menu.tsx +++ b/apps/nextjs/src/components/user-avatar-menu.tsx @@ -31,8 +31,6 @@ interface UserAvatarMenuProps { children: ReactNode; availableUpdates?: RouterOutputs["updateChecker"]["getAvailableUpdates"]; isDockerEnabled?: boolean; - opened: boolean; - onOpenChange: (opened: boolean) => void; } const formatHotkeyLabel = (hotkey: string, modifierLabel: string) => @@ -41,13 +39,7 @@ const formatHotkeyLabel = (hotkey: string, modifierLabel: string) => .map((key) => (key === "mod" ? modifierLabel : `${key.charAt(0).toUpperCase()}${key.slice(1)}`)) .join(" + "); -export const UserAvatarMenu = ({ - children, - availableUpdates, - isDockerEnabled, - opened, - onOpenChange, -}: UserAvatarMenuProps) => { +export const UserAvatarMenu = ({ children, availableUpdates, isDockerEnabled }: UserAvatarMenuProps) => { const t = useScopedI18n("common.userAvatar.menu"); const session = useSession(); @@ -65,7 +57,7 @@ export const UserAvatarMenu = ({ return ( // We use keepMounted so we can add event listeners to prevent navigating away without saving the board - + }> diff --git a/apps/nextjs/src/components/workshop-install/install-from-workshop-buttons.tsx b/apps/nextjs/src/components/workshop-install/install-from-workshop-buttons.tsx deleted file mode 100644 index 855c7ee36..000000000 --- a/apps/nextjs/src/components/workshop-install/install-from-workshop-buttons.tsx +++ /dev/null @@ -1,98 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { Button } from "@mantine/core"; -import { useDisclosure } from "@mantine/hooks"; -import { IconUsersGroup } from "@tabler/icons-react"; - -import { clientApi } from "@homarr/api/client"; -import { revalidatePathActionAsync } from "@homarr/common/client"; -import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; -import { useScopedI18n } from "@homarr/translation/client"; -import { customWidgetImportSchema } from "@homarr/validation/custom-widget"; - -import { MobileAffixButton } from "~/components/manage/mobile-affix-button"; -import { WorkshopBrowserModal } from "./workshop-browser-modal"; - -function parseWidgetContent(content: string) { - let parsed: unknown; - try { - parsed = JSON.parse(content); - } catch { - return { ok: false as const, message: "Submission content is not valid JSON" }; - } - const result = customWidgetImportSchema.safeParse(parsed); - if (!result.success) { - return { ok: false as const, message: result.error.issues[0]?.message ?? "Invalid widget schema" }; - } - return { ok: true as const, data: result.data }; -} - -export const InstallWidgetFromWorkshopButton = () => { - const t = useScopedI18n("customWidget.workshop"); - const [opened, { open, close }] = useDisclosure(false); - const [pendingId, setPendingId] = useState(null); - const utils = clientApi.useUtils(); - const importMutation = clientApi.customWidget.import.useMutation({ - onSuccess: () => { - showSuccessNotification({ title: t("title"), message: t("notification.widgetInstalled") }); - void utils.customWidget.all.invalidate(); - void revalidatePathActionAsync("/manage/custom-widgets"); - setPendingId(null); - close(); - }, - onError: (err) => { - showErrorNotification({ title: t("title"), message: err.message || t("notification.widgetInstallFailed") }); - setPendingId(null); - }, - }); - - const handleSelect = (submission: { id: string; content: string }) => { - const parsed = parseWidgetContent(submission.content); - if (!parsed.ok) { - showErrorNotification({ title: t("title"), message: parsed.message }); - return; - } - setPendingId(submission.id); - importMutation.mutate(parsed.data); - }; - - return ( - <> - } onClick={open}> - {t("action.installFromWorkshop")} - - - - ); -}; - -export const InstallCssFromWorkshopButton = ({ onSelect }: { onSelect: (css: string) => void }) => { - const t = useScopedI18n("customWidget.workshop"); - const [opened, { open, close }] = useDisclosure(false); - - return ( - <> - - { - onSelect(submission.content); - close(); - }} - /> - - ); -}; diff --git a/apps/nextjs/src/components/workshop-install/workshop-api.ts b/apps/nextjs/src/components/workshop-install/workshop-api.ts deleted file mode 100644 index 4a8b6d1e2..000000000 --- a/apps/nextjs/src/components/workshop-install/workshop-api.ts +++ /dev/null @@ -1,47 +0,0 @@ -export const WORKSHOP_API_URL = process.env.NEXT_PUBLIC_WORKSHOP_API_URL || "https://workshop.homarr.dev"; - -export interface WorkshopSubmission { - id: string; - collectionId: string; - collectionName: string; - type: "css" | "widget"; - title: string; - description: string; - schemaVersion: string; - content: string; - screenshots: string[]; - upvotes: number; - downvotes: number; - version: number; - author: string; - authorName: string; - commentCount: number; - created: string; -} - -interface PBListResponse { - page: number; - perPage: number; - totalPages: number; - totalItems: number; - items: WorkshopSubmission[]; -} - -export const getWorkshopFileUrl = (submission: WorkshopSubmission, filename: string) => - `${WORKSHOP_API_URL}/api/files/submissions/${submission.id}/${encodeURIComponent(filename)}`; - -export const fetchWorkshopSubmissions = async ( - type: "css" | "widget", - page = 1, - perPage = 50, -): Promise => { - const params = new URLSearchParams({ - page: String(page), - perPage: String(perPage), - sort: "-upvotes", - filter: `(type='${type}')`, - }); - const response = await fetch(`${WORKSHOP_API_URL}/api/collections/marketplace/records?${params}`); - if (!response.ok) throw new Error(`Workshop request failed (${response.status})`); - return response.json() as Promise; -}; diff --git a/apps/nextjs/src/components/workshop-install/workshop-browser-modal.tsx b/apps/nextjs/src/components/workshop-install/workshop-browser-modal.tsx deleted file mode 100644 index 1ee2da459..000000000 --- a/apps/nextjs/src/components/workshop-install/workshop-browser-modal.tsx +++ /dev/null @@ -1,221 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { - ActionIcon, - Anchor, - Alert, - Badge, - Box, - Button, - Card, - Center, - Group, - Image, - Loader, - Modal, - Pagination, - ScrollArea, - SimpleGrid, - Stack, - Text, -} from "@mantine/core"; -import { IconChevronLeft, IconChevronRight, IconExternalLink } from "@tabler/icons-react"; -import { useQuery } from "@tanstack/react-query"; - -import type { WorkshopSubmission } from "./workshop-api"; -import { fetchWorkshopSubmissions, getWorkshopFileUrl } from "./workshop-api"; - -const WORKSHOP_URL = process.env.NEXT_PUBLIC_WORKSHOP_URL || "https://homarr.dev/workshop"; - -interface Props { - type: "css" | "widget"; - opened: boolean; - onClose: () => void; - onSelect: (submission: WorkshopSubmission) => void; - actionLabel: string; - pendingId?: string | null; -} - -const displayName = (submission: WorkshopSubmission) => submission.authorName; - -export const WorkshopBrowserModal = ({ type, opened, onClose, onSelect, actionLabel, pendingId }: Props) => { - const [page, setPage] = useState(1); - const handleClose = () => { - setPage(1); - onClose(); - }; - const { data, isLoading, error } = useQuery({ - queryKey: ["workshop-submissions", type, page], - queryFn: () => fetchWorkshopSubmissions(type, page), - enabled: opened, - }); - - const errorText = error instanceof Error ? error.message : "unknown error"; - - return ( - - Install from Workshop - - Open Workshop - - - } - size={1200} - scrollAreaComponent={ScrollArea.Autosize} - > - - {isLoading && ( -
    - -
    - )} - - {error && Failed to load the workshop: {errorText}} - - {data && data.items.length === 0 && ( - - No submissions available yet. - - )} - - {data && data.items.length > 0 && ( - <> - - {data.items.map((submission) => ( - onSelect(submission)} - /> - ))} - - - {data.totalPages > 1 && ( -
    - -
    - )} - - )} -
    -
    - ); -}; - -const SubmissionCard = ({ - submission, - actionLabel, - pending, - onSelect, -}: { - submission: WorkshopSubmission; - actionLabel: string; - pending: boolean; - onSelect: () => void; -}) => { - const screenshots = submission.screenshots ?? []; - const [imgIdx, setImgIdx] = useState(0); - const score = submission.upvotes - submission.downvotes; - const scorePrefix = score > 0 ? "+" : ""; - - return ( - - {screenshots.length > 0 && ( - - {submission.title} - {screenshots.length > 1 && ( - <> - setImgIdx((i) => (i - 1 + screenshots.length) % screenshots.length)} - > - - - setImgIdx((i) => (i + 1) % screenshots.length)} - > - - - - )} - - )} - - - - - - {submission.title} - - - {scorePrefix} - {score} - - - - - {displayName(submission)} · v{submission.version} - - - {submission.description && ( - - {submission.description} - - )} - - - - - - - - - - ); -}; diff --git a/apps/workshop/pb_migrations/1750000000_init_workshop.js b/apps/workshop/pb_migrations/1750000000_init_workshop.js deleted file mode 100644 index 6fc1d7d0c..000000000 --- a/apps/workshop/pb_migrations/1750000000_init_workshop.js +++ /dev/null @@ -1,172 +0,0 @@ -/// - -migrate( - (app) => { - const users = app.findCollectionByNameOrId("users"); - - const githubClientId = $os.getenv("GITHUB_CLIENT_ID"); - const githubClientSecret = $os.getenv("GITHUB_CLIENT_SECRET"); - if (githubClientId && githubClientSecret) { - users.oauth2.enabled = true; - users.oauth2.providers = [ - { - name: "github", - clientId: githubClientId, - clientSecret: githubClientSecret, - }, - ]; - } - app.save(users); - - let submissions; - try { - submissions = app.findCollectionByNameOrId("submissions"); - } catch { - submissions = new Collection({ - type: "base", - name: "submissions", - listRule: "", - viewRule: "", - createRule: "@request.auth.id != ''", - updateRule: "author = @request.auth.id", - deleteRule: "author = @request.auth.id", - fields: [ - { name: "type", type: "select", required: true, maxSelect: 1, values: ["css", "widget"] }, - { name: "title", type: "text", required: true, min: 3, max: 100 }, - { name: "description", type: "text", max: 2000 }, - { name: "schemaVersion", type: "text", required: true, max: 100 }, - { name: "content", type: "text", required: true, max: 1000000 }, - { - name: "screenshots", - type: "file", - maxSelect: 5, - maxSize: 5242880, - mimeTypes: ["image/png", "image/jpeg", "image/webp", "image/gif"], - }, - { - name: "author", - type: "relation", - required: true, - maxSelect: 1, - collectionId: users.id, - cascadeDelete: true, - }, - { name: "upvotes", type: "number", onlyInt: true }, - { name: "downvotes", type: "number", onlyInt: true }, - { name: "version", type: "number", onlyInt: true }, - { name: "changelog", type: "text", max: 2000 }, - { name: "created", type: "autodate", onCreate: true }, - { name: "updated", type: "autodate", onCreate: true, onUpdate: true }, - ], - }); - app.save(submissions); - } - - let votes; - try { - votes = app.findCollectionByNameOrId("votes"); - } catch { - votes = new Collection({ - type: "base", - name: "votes", - listRule: "user = @request.auth.id", - viewRule: "user = @request.auth.id", - createRule: "@request.auth.id != ''", - updateRule: "user = @request.auth.id", - deleteRule: "user = @request.auth.id", - fields: [ - { - name: "submission", - type: "relation", - required: true, - maxSelect: 1, - collectionId: submissions.id, - cascadeDelete: true, - }, - { name: "user", type: "relation", required: true, maxSelect: 1, collectionId: users.id, cascadeDelete: true }, - { name: "value", type: "number", required: true, onlyInt: true, min: -1, max: 1 }, - { name: "created", type: "autodate", onCreate: true }, - { name: "updated", type: "autodate", onCreate: true, onUpdate: true }, - ], - }); - votes.addIndex("idx_votes_unique_user_submission", true, "submission, user", ""); - app.save(votes); - } - - let reports; - try { - reports = app.findCollectionByNameOrId("reports"); - } catch { - reports = new Collection({ - type: "base", - name: "reports", - listRule: null, - viewRule: null, - createRule: "@request.auth.id != ''", - updateRule: null, - deleteRule: null, - fields: [ - { - name: "submission", - type: "relation", - required: true, - maxSelect: 1, - collectionId: submissions.id, - cascadeDelete: true, - }, - { name: "user", type: "relation", required: true, maxSelect: 1, collectionId: users.id, cascadeDelete: true }, - { name: "reason", type: "text", required: true, min: 3, max: 1000 }, - { name: "created", type: "autodate", onCreate: true }, - ], - }); - app.save(reports); - } - - let comments; - try { - comments = app.findCollectionByNameOrId("comments"); - } catch { - comments = new Collection({ - type: "base", - name: "comments", - listRule: "", - viewRule: "", - createRule: "@request.auth.id != ''", - updateRule: "author = @request.auth.id", - deleteRule: "author = @request.auth.id", - fields: [ - { - name: "submission", - type: "relation", - required: true, - maxSelect: 1, - collectionId: submissions.id, - cascadeDelete: true, - }, - { - name: "author", - type: "relation", - required: true, - maxSelect: 1, - collectionId: users.id, - cascadeDelete: true, - }, - { name: "content", type: "text", required: true, min: 1, max: 2000 }, - { name: "created", type: "autodate", onCreate: true }, - { name: "updated", type: "autodate", onCreate: true, onUpdate: true }, - ], - }); - comments.addIndex("idx_comments_submission", false, "submission", ""); - app.save(comments); - } - }, - (app) => { - for (const name of ["comments", "reports", "votes", "submissions"]) { - try { - app.delete(app.findCollectionByNameOrId(name)); - } catch { - // already gone - } - } - }, -); diff --git a/apps/workshop/pb_migrations/1750000002_marketplace_view.js b/apps/workshop/pb_migrations/1750000002_marketplace_view.js deleted file mode 100644 index dbd62046b..000000000 --- a/apps/workshop/pb_migrations/1750000002_marketplace_view.js +++ /dev/null @@ -1,49 +0,0 @@ -/// - -migrate( - (app) => { - // Keep databases created by the original prototype valid after the - // migration file was renamed with the feature. - try { - app.findCollectionByNameOrId("marketplace"); - return; - } catch { - // Fresh database; create the public view below. - } - - const collection = new Collection({ - name: "marketplace", - type: "view", - listRule: "", - viewRule: "", - viewQuery: ` - SELECT - s.id, - s.type, - s.title, - s.description, - s.schemaVersion, - s.content, - s.screenshots, - s.version, - s.changelog, - s.author, - s.created, - s.updated, - COALESCE(NULLIF(u.name, ''), 'unknown') as authorName, - COALESCE(SUM(CASE WHEN v.value = 1 THEN 1 ELSE 0 END), 0) as upvotes, - COALESCE(SUM(CASE WHEN v.value = -1 THEN 1 ELSE 0 END), 0) as downvotes, - (SELECT COUNT(*) FROM comments c WHERE c.submission = s.id) as commentCount - FROM submissions s - LEFT JOIN users u ON u.id = s.author - LEFT JOIN votes v ON v.submission = s.id - GROUP BY s.id - `, - }); - app.save(collection); - }, - (app) => { - const collection = app.findCollectionByNameOrId("marketplace"); - app.delete(collection); - }, -); diff --git a/apps/workshop/scripts/smoke-test.sh b/apps/workshop/scripts/smoke-test.sh deleted file mode 100755 index 57dc55d46..000000000 --- a/apps/workshop/scripts/smoke-test.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh -set -eu - -image="${1:-homarr/workshop:ci}" -container="homarr-workshop-smoke-${$}" -port="${WORKSHOP_SMOKE_PORT:-18090}" - -cleanup() { - docker rm --force "$container" >/dev/null 2>&1 || true -} -trap cleanup EXIT INT TERM - -docker run --detach --name "$container" --publish "127.0.0.1:${port}:8090" "$image" >/dev/null - -attempt=0 -until curl --fail --silent "http://127.0.0.1:${port}/api/health" >/dev/null; do - attempt=$((attempt + 1)) - if [ "$attempt" -ge 30 ]; then - docker logs "$container" - exit 1 - fi - sleep 1 -done - -curl --fail --silent "http://127.0.0.1:${port}/" | grep --quiet "Homarr" -curl --fail --silent "http://127.0.0.1:${port}/workshop/" | grep --quiet "Workshop" -curl --fail --silent "http://127.0.0.1:${port}/api/collections/marketplace/records?page=1&perPage=1" >/dev/null -curl --fail --silent "http://127.0.0.1:${port}/api/health" | grep --quiet '"code":200' - -echo "Workshop image serves Docusaurus and PocketBase successfully" diff --git a/e2e/board-advanced-interactions.spec.ts b/e2e/board-advanced-interactions.spec.ts index ba8f892d9..b970eec28 100644 --- a/e2e/board-advanced-interactions.spec.ts +++ b/e2e/board-advanced-interactions.spec.ts @@ -1,4 +1,4 @@ -import type { Browser, BrowserContext, Locator, Page } from "@playwright/test"; +import type { Browser, BrowserContext, Page } from "@playwright/test"; import { chromium, expect } from "@playwright/test"; import { createId } from "@paralleldrive/cuid2"; import { eq } from "drizzle-orm"; @@ -26,7 +26,6 @@ const ownerCredentials = { username: "owner", password: "Comp(exP4sswOrd" }; const disabledModifierCredentials = { username: "modifier", password: "Comp(exP4sswOrd" }; const viewerCredentials = { username: "viewer", password: "Comp(exP4sswOrd" }; const boardName = "advanced-interactions-e2e"; -const emptyCellCenterXRatio = 7.5 / 12; describe("Board advanced interactions", () => { let browser: Browser; @@ -68,13 +67,15 @@ describe("Board advanced interactions", () => { const { context, page } = await openBoardAsync(browser, baseUrl, ownerCredentials); try { - const widget = page.locator(".grid-stack-item[data-kind='clock'] > .grid-stack-item-content").first(); + const widget = page.locator("[data-grid-item-id][data-kind='clock'] [data-advanced-focus-source]").first(); const compactSurface = page.locator(".clock-wrapper").first(); const previewSurface = page.getByRole("region", { name: "Date and time advanced view" }); const manualSurface = page.getByRole("dialog", { name: "Date and time advanced view" }); const bookmarksPreviewSurface = page.getByRole("region", { name: "Bookmarks advanced view" }); const dimmingOverlay = page.locator("[data-advanced-focus-overlay]"); - const otherWidget = page.locator(".grid-stack-item[data-kind='bookmarks'] > .grid-stack-item-content").first(); + const otherWidget = page + .locator("[data-grid-item-id][data-kind='bookmarks'] [data-advanced-focus-source]") + .first(); const header = page.locator("header[data-advanced-focus-background]"); const boardMain = page.locator("main[data-advanced-focus-background]"); @@ -146,7 +147,7 @@ describe("Board advanced interactions", () => { await expect(manualSurface).toHaveAttribute("aria-modal", "true"); await expect(header).toHaveAttribute("inert", ""); await expect(boardMain).toHaveAttribute("inert", ""); - expect(await manualSurface.evaluate((element) => element.closest(".grid-stack-item"))).toBeNull(); + expect(await manualSurface.evaluate((element) => element.closest("[data-grid-item-id]"))).toBeNull(); await expect(manualSurface.locator(".clock-wrapper")).toHaveAttribute("data-lifecycle-probe", "same-instance"); await expect(dimmingOverlay).toHaveCSS("pointer-events", "auto"); expect(await page.evaluate(() => getComputedStyle(document.body).overflow)).toBe("hidden"); @@ -235,7 +236,7 @@ describe("Board advanced interactions", () => { for (const compactOnlyKind of ["app", "iframe"]) { const compactOnlyWidget = page - .locator(`.grid-stack-item[data-kind='${compactOnlyKind}'] > .grid-stack-item-content`) + .locator(`[data-grid-item-id][data-kind='${compactOnlyKind}'] [data-advanced-focus-source]`) .first(); await expect(compactOnlyWidget).not.toHaveAttribute("aria-keyshortcuts", "Shift+Enter"); await compactOnlyWidget.dispatchEvent("contextmenu", { button: 2 }); @@ -256,7 +257,7 @@ describe("Board advanced interactions", () => { const { context, page } = await openBoardAsync(browser, baseUrl, ownerCredentials); try { - const iframeSlot = page.locator(".grid-stack-item[data-kind='iframe'] > .grid-stack-item-content").first(); + const iframeSlot = page.locator("[data-grid-item-id][data-kind='iframe'] [data-advanced-focus-source]").first(); const iframe = iframeSlot.locator("iframe"); await iframe.evaluate((element) => { (element as HTMLIFrameElement).srcdoc = ''; @@ -275,13 +276,15 @@ describe("Board advanced interactions", () => { await page.keyboard.up("Shift"); await expect(frame.locator("#state")).toHaveValue("changed"); - const bookmarksSlot = page.locator(".grid-stack-item[data-kind='bookmarks'] > .grid-stack-item-content").first(); + const bookmarksSlot = page + .locator("[data-grid-item-id][data-kind='bookmarks'] [data-advanced-focus-source]") + .first(); await bookmarksSlot.focus(); await page.keyboard.press("Shift+Enter"); await expect(page.getByRole("dialog", { name: "Bookmarks advanced view" })).toBeVisible(); await page.setViewportSize({ width: 800, height: 900 }); await expect(page.getByRole("dialog", { name: "Bookmarks advanced view" })).toBeHidden(); - await expect(page.locator(".grid-stack-item[data-kind='iframe'] iframe")).toBeVisible(); + await expect(page.locator("[data-grid-item-id][data-kind='iframe'] iframe")).toBeVisible(); } finally { await context.close(); } @@ -291,7 +294,7 @@ describe("Board advanced interactions", () => { const { context, page } = await openBoardAsync(browser, baseUrl, ownerCredentials, { width: 1366, height: 768 }); try { - const widget = page.locator(".grid-stack-item[data-kind='clock'] > .grid-stack-item-content").first(); + const widget = page.locator("[data-grid-item-id][data-kind='clock'] [data-advanced-focus-source]").first(); await widget.focus(); await page.keyboard.press("Shift+Enter"); const closeButton = page.getByRole("button", { name: "Close advanced view" }); @@ -321,70 +324,29 @@ describe("Board advanced interactions", () => { } }, 60_000); - test("opens the add-at-position chooser only when right click and change access are enabled", async () => { - const { context, page } = await openBoardAsync(browser, baseUrl, ownerCredentials); - - try { - const grid = page.locator(".grid-stack[data-kind='empty']"); - const addHereMenuItem = page.getByRole("menuitem", { name: "Add item here" }); - await expect(grid).toHaveAttribute("aria-label", "Add item here"); - - await grid.press("Shift+F10"); - await expect(addHereMenuItem).toBeFocused(); - await page.keyboard.press("Enter"); - await expect(page.getByRole("dialog").filter({ hasText: "Choose item to add" })).toBeVisible(); - await page.keyboard.press("Escape"); - await expect(grid).toBeFocused(); - - await touchAndHoldEmptyGridSpaceAsync(grid); - await expect(addHereMenuItem).toBeVisible({ timeout: 1_000 }); - await page.keyboard.press("Escape"); - await expect(addHereMenuItem).toBeHidden(); - await expect(grid).toBeFocused(); - - await rightClickEmptyGridSpaceAsync(grid); - await expect(addHereMenuItem).toBeVisible(); - await addHereMenuItem.click(); - await expect(page.getByRole("dialog").filter({ hasText: "Choose item to add" })).toBeVisible(); - await page.keyboard.press("Escape"); - await expect(grid).toBeFocused(); - } finally { - await context.close(); - } - }, 60_000); - test("honors the user setting gate even when the user can modify the board", async () => { const { context, page } = await openBoardAsync(browser, baseUrl, disabledModifierCredentials); try { - const widget = page.locator(".grid-stack-item[data-kind='clock'] > .grid-stack-item-content").first(); - const grid = page.locator(".grid-stack[data-kind='empty']"); + const widget = page.locator("[data-grid-item-id][data-kind='clock'] [data-advanced-focus-source]").first(); await widget.click({ button: "right" }); await expect(page.getByRole("menuitem", { name: "Open advanced view" })).toHaveCount(0); - await expect(grid).not.toHaveAttribute("aria-label", "Add item here"); - await rightClickEmptyGridSpaceAsync(grid); - await expect(page.getByRole("menuitem", { name: "Add item here" })).toHaveCount(0); } finally { await context.close(); } }, 60_000); - test("keeps read-only advanced viewing but blocks add-at-position without change access", async () => { + test("keeps read-only advanced viewing", async () => { const { context, page } = await openBoardAsync(browser, baseUrl, viewerCredentials); try { - const widget = page.locator(".grid-stack-item[data-kind='clock'] > .grid-stack-item-content").first(); - const grid = page.locator(".grid-stack[data-kind='empty']"); + const widget = page.locator("[data-grid-item-id][data-kind='clock'] [data-advanced-focus-source]").first(); await widget.click({ button: "right" }); await page.getByRole("menuitem", { name: "Open advanced view" }).click(); await expect(page.getByRole("dialog", { name: "Date and time advanced view" })).toBeVisible(); await page.keyboard.press("Escape"); - - await expect(grid).not.toHaveAttribute("aria-label", "Add item here"); - await rightClickEmptyGridSpaceAsync(grid); - await expect(page.getByRole("menuitem", { name: "Add item here" })).toHaveCount(0); } finally { await context.close(); } @@ -408,29 +370,6 @@ const openBoardAsync = async ( return { context, page }; }; -const rightClickEmptyGridSpaceAsync = async (grid: Locator) => { - const bounds = await grid.boundingBox(); - expect(bounds).not.toBeNull(); - if (!bounds) return; - - await grid.click({ - button: "right", - position: { x: bounds.width * emptyCellCenterXRatio, y: Math.min(24, bounds.height / 2) }, - }); -}; - -const touchAndHoldEmptyGridSpaceAsync = async (grid: Locator) => { - const bounds = await grid.boundingBox(); - expect(bounds).not.toBeNull(); - if (!bounds) return; - - const clientX = bounds.x + bounds.width * emptyCellCenterXRatio; - const clientY = bounds.y + Math.min(24, bounds.height / 2); - await grid.dispatchEvent("pointerdown", { pointerType: "touch", clientX, clientY }); - await new Promise((resolve) => setTimeout(resolve, 800)); - await grid.dispatchEvent("pointerup", { pointerType: "touch", clientX, clientY }); -}; - const seedInteractionBoardAsync = async (db: SqliteDatabase, ownerId: string) => { const boardId = createId(); const baseLayoutId = createId(); diff --git a/e2e/custom-widgets-custom-jsx-v2.spec.ts b/e2e/custom-widgets-custom-jsx-v2.spec.ts index a88ca1944..fbfdcc7d2 100644 --- a/e2e/custom-widgets-custom-jsx-v2.spec.ts +++ b/e2e/custom-widgets-custom-jsx-v2.spec.ts @@ -36,7 +36,10 @@ describe("Custom JSX v2 workbench", () => { await page.waitForLoadState("networkidle"); await page.getByLabel("Username").fill(adminCredentials.username); await page.locator("#password").fill(adminCredentials.password); - const signedIn = page.waitForURL(baseUrl, { waitUntil: "commit", timeout: 15_000 }); + const signedIn = page.waitForURL((url) => url.origin === baseUrl && url.pathname !== "/auth/login", { + waitUntil: "commit", + timeout: 60_000, + }); await page.locator("button[type='submit']").click(); await signedIn; diff --git a/packages/api/src/mcp.ts b/packages/api/src/mcp.ts index 2f1a81822..06d023863 100644 --- a/packages/api/src/mcp.ts +++ b/packages/api/src/mcp.ts @@ -16,7 +16,6 @@ import { bazarrRouter } from "./router/widgets/bazarr"; import { serverSettingsRouter } from "./router/serverSettings"; import { beszelRouter } from "./router/widgets/beszel"; import { calendarRouter } from "./router/widgets/calendar"; -import { customWidgetRouter } from "./router/custom-widget/custom-widget-router"; import { dnsHoleRouter } from "./router/widgets/dns-hole"; import { downloadsRouter } from "./router/widgets/downloads"; import { healthMonitoringRouter } from "./router/widgets/health-monitoring"; @@ -40,7 +39,6 @@ export const mcpRouter = createTRPCRouter({ serverSettings: serverSettingsRouter, beszel: beszelRouter, calendar: calendarRouter, - customWidget: customWidgetRouter, dnsHole: dnsHoleRouter, downloads: downloadsRouter, healthMonitoring: healthMonitoringRouter, diff --git a/packages/api/src/router/test/board.spec.ts b/packages/api/src/router/test/board.spec.ts index bab1040a4..dbbb7f25c 100644 --- a/packages/api/src/router/test/board.spec.ts +++ b/packages/api/src/router/test/board.spec.ts @@ -1853,47 +1853,6 @@ describe("saveLayouts should save layout changes", () => { expect(basePosition).toMatchObject({ xOffset: 0, yOffset: 1, width: 4, height: 1, sectionId }); expect(customPosition).toMatchObject({ xOffset: 0, yOffset: 1, width: 4, height: 1, sectionId }); }); - test("should project a new custom layout from the resized Base layout", async () => { - const db = createDb(); - const caller = boardRouter.createCaller({ db, deviceType: undefined, session: defaultSession }); - const { boardId, layoutId, sectionId, itemId } = await createFullBoardAsync(db, "default"); - const mobileLayoutId = await addMobileLayoutAsync(db, boardId); - const secondItemId = createId(); - - await db.update(itemLayouts).set({ width: 4, xOffset: 0 }).where(eq(itemLayouts.itemId, itemId)); - await db.insert(items).values({ - id: secondItemId, - kind: "clock", - boardId, - options: SuperJSON.stringify({ is24HourFormat: true }), - }); - await db.insert(itemLayouts).values({ - itemId: secondItemId, - layoutId, - sectionId, - width: 4, - height: 1, - xOffset: 6, - yOffset: 0, - }); - - const resizedBase = { ...createExistingLayout(layoutId), columnCount: 6 }; - const savedLayouts = await caller.saveLayouts({ - id: boardId, - layouts: [createMobileLayout(mobileLayoutId), createNewLayout(8), resizedBase], - }); - const customLayoutId = expectToBeDefined(savedLayouts.find((layout) => layout.role === "custom")).id; - - const basePosition = await db.query.itemLayouts.findFirst({ - where: and(eq(itemLayouts.itemId, secondItemId), eq(itemLayouts.layoutId, layoutId)), - }); - const customPosition = await db.query.itemLayouts.findFirst({ - where: and(eq(itemLayouts.itemId, secondItemId), eq(itemLayouts.layoutId, customLayoutId)), - }); - - expect(basePosition).toMatchObject({ xOffset: 0, yOffset: 1, width: 4, height: 1, sectionId }); - expect(customPosition).toMatchObject({ xOffset: 0, yOffset: 1, width: 4, height: 1, sectionId }); - }); test("should remove layout when not present in input", async () => { // Arrange const db = createDb(); diff --git a/packages/api/src/router/test/custom-widget.spec.ts b/packages/api/src/router/test/custom-widget.spec.ts deleted file mode 100644 index b026b2f68..000000000 --- a/packages/api/src/router/test/custom-widget.spec.ts +++ /dev/null @@ -1,376 +0,0 @@ -// @vitest-environment node - -import { stringify } from "superjson"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; - -import type { Session } from "@homarr/auth"; -import { createId } from "@homarr/common"; -import type { Database } from "@homarr/db"; -import { eq } from "@homarr/db"; -import { boards, boardUserPermissions, customWidgetDefinitions, items, users } from "@homarr/db/schema"; -import { createDb } from "@homarr/db/test"; -import type { GroupPermissionKey } from "@homarr/definitions"; - -import { customWidgetRouter } from "../custom-widget/custom-widget-router"; -import { customApiRouter } from "../widgets/custom-api"; - -const createSession = (userId: string, permissions: GroupPermissionKey[] = []): Session => ({ - user: { id: userId, permissions, colorScheme: "light" }, - expires: new Date().toISOString(), -}); - -const createCustomWidgetCaller = (db: Database, session: Session | null) => - customWidgetRouter.createCaller({ db, deviceType: undefined, session }); - -const createCustomApiCaller = (db: Database, session: Session | null) => - customApiRouter.createCaller({ db, deviceType: undefined, session }); - -async function createFixtureAsync(db: Database) { - const ownerId = createId(); - const viewerId = createId(); - const modifierId = createId(); - const unrelatedId = createId(); - const adminId = createId(); - const boardId = createId(); - const itemId = createId(); - const definitionId = createId(); - - await db.insert(users).values( - [ownerId, viewerId, modifierId, unrelatedId, adminId].map((id) => ({ - id, - name: id, - })), - ); - await db.insert(boards).values({ id: boardId, name: `board-${boardId}`, creatorId: ownerId, isPublic: false }); - await db.insert(boardUserPermissions).values([ - { boardId, userId: viewerId, permission: "view" }, - { boardId, userId: modifierId, permission: "modify" }, - ]); - await db.insert(customWidgetDefinitions).values({ - id: definitionId, - name: "Restart service", - description: "Restarts a service", - url: "https://api.example.com/restart", - method: "POST", - displayType: "actionButton", - displayConfig: stringify({ - type: "actionButton", - buttonLabel: "Restart", - confirmText: "Continue?", - }), - creatorId: adminId, - }); - await db.insert(items).values({ - id: itemId, - boardId, - kind: "customApi", - options: stringify({ definitionId, refreshInterval: 30 }), - }); - - return { ownerId, viewerId, modifierId, unrelatedId, adminId, boardId, itemId, definitionId }; -} - -beforeEach(() => { - vi.restoreAllMocks(); - vi.useRealTimers(); -}); - -afterEach(() => { - vi.unstubAllGlobals(); - vi.useRealTimers(); -}); - -describe("custom widget definition authorization", () => { - it("restricts the full definition list to administrators", async () => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - - await expect(createCustomWidgetCaller(db, null).all()).rejects.toMatchObject({ code: "UNAUTHORIZED" }); - for (const userId of [fixture.ownerId, fixture.viewerId, fixture.modifierId, fixture.unrelatedId]) { - await expect(createCustomWidgetCaller(db, createSession(userId)).all()).rejects.toMatchObject({ - code: "FORBIDDEN", - }); - } - - await expect(createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).all()).resolves.toEqual([ - expect.objectContaining({ id: fixture.definitionId, url: "https://api.example.com/restart" }), - ]); - }); - - it("returns only safe definition summaries to board modifiers", async () => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - - const result = await createCustomWidgetCaller(db, createSession(fixture.modifierId)).available({ - boardId: fixture.boardId, - }); - expect(result).toEqual([ - { - id: fixture.definitionId, - name: "Restart service", - description: "Restarts a service", - iconUrl: null, - displayType: "actionButton", - enabled: true, - }, - ]); - expect(JSON.stringify(result)).not.toContain("api.example.com"); - - for (const userId of [fixture.viewerId, fixture.unrelatedId]) { - await expect( - createCustomWidgetCaller(db, createSession(userId)).available({ boardId: fixture.boardId }), - ).rejects.toMatchObject({ code: "NOT_FOUND" }); - } - }); -}); - -describe("custom widget action authorization", () => { - it("requires an administrator even for users who can view or modify the board", async () => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - const input = { - boardId: fixture.boardId, - itemId: fixture.itemId, - definitionId: fixture.definitionId, - }; - - await expect(createCustomWidgetCaller(db, null).execute(input)).rejects.toMatchObject({ code: "UNAUTHORIZED" }); - for (const userId of [fixture.ownerId, fixture.viewerId, fixture.modifierId, fixture.unrelatedId]) { - await expect(createCustomWidgetCaller(db, createSession(userId)).execute(input)).rejects.toMatchObject({ - code: "FORBIDDEN", - }); - } - }); - - it("executes for an administrator only when board, item, and definition are bound", async () => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - const fetchMock = vi.fn().mockResolvedValue(new Response(null, { status: 204 })); - vi.stubGlobal("fetch", fetchMock); - const caller = createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])); - - await expect( - caller.execute({ - boardId: fixture.boardId, - itemId: fixture.itemId, - definitionId: fixture.definitionId, - }), - ).resolves.toEqual({ success: true, responseInfo: { status: 204 } }); - expect(fetchMock).toHaveBeenCalledWith( - "https://api.example.com/restart", - expect.objectContaining({ method: "POST", redirect: "error", signal: expect.any(AbortSignal) }), - ); - }); - - it.each(["board", "item", "definition"] as const)("rejects a mismatched %s binding", async (mismatch) => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - const fetchMock = vi.fn(); - vi.stubGlobal("fetch", fetchMock); - const input = { - boardId: mismatch === "board" ? createId() : fixture.boardId, - itemId: mismatch === "item" ? createId() : fixture.itemId, - definitionId: mismatch === "definition" ? createId() : fixture.definitionId, - }; - - await expect( - createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute(input), - ).rejects.toMatchObject({ code: "NOT_FOUND" }); - expect(fetchMock).not.toHaveBeenCalled(); - }); - - it("rejects disabled definitions before sending a request", async () => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - await db - .update(customWidgetDefinitions) - .set({ enabled: false }) - .where(eq(customWidgetDefinitions.id, fixture.definitionId)); - const fetchMock = vi.fn(); - vi.stubGlobal("fetch", fetchMock); - - await expect( - createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute({ - boardId: fixture.boardId, - itemId: fixture.itemId, - definitionId: fixture.definitionId, - }), - ).rejects.toMatchObject({ code: "FORBIDDEN" }); - expect(fetchMock).not.toHaveBeenCalled(); - }); -}); - -describe("custom API outbound request hardening", () => { - it("rejects credential-bearing action URLs without exposing the credential", async () => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - await db - .update(customWidgetDefinitions) - .set({ url: "https://operator:super-secret@private.example.com/restart" }) - .where(eq(customWidgetDefinitions.id, fixture.definitionId)); - const fetchMock = vi.fn(); - vi.stubGlobal("fetch", fetchMock); - - const result = await createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute({ - boardId: fixture.boardId, - itemId: fixture.itemId, - definitionId: fixture.definitionId, - }); - expect(result).toEqual({ success: false, errorCode: "REQUEST_FAILED", responseInfo: null }); - expect(JSON.stringify(result)).not.toMatch(/super-secret|private\.example\.com/); - expect(fetchMock).not.toHaveBeenCalled(); - }); - - it("rejects redirects and redacts fetch errors", async () => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - const fetchMock = vi - .fn() - .mockRejectedValue( - new TypeError("Redirect to http://token:secret@internal.example.local/admin?apiKey=top-secret was rejected"), - ); - vi.stubGlobal("fetch", fetchMock); - - const result = await createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute({ - boardId: fixture.boardId, - itemId: fixture.itemId, - definitionId: fixture.definitionId, - }); - expect(fetchMock).toHaveBeenCalledWith( - "https://api.example.com/restart", - expect.objectContaining({ redirect: "error" }), - ); - expect(result).toEqual({ success: false, errorCode: "REQUEST_FAILED", responseInfo: null }); - expect(JSON.stringify(result)).not.toMatch(/top-secret|internal\.example\.local|apiKey/); - }); - - it("aborts timed-out action requests and returns a stable failure", async () => { - vi.useFakeTimers(); - const db = createDb(); - const fixture = await createFixtureAsync(db); - const started = Promise.withResolvers(); - const fetchMock = vi.fn((_url: string, init: RequestInit) => { - started.resolve(); - return new Promise((_resolve, reject) => { - init.signal?.addEventListener("abort", () => { - reject(new Error("Timed out calling http://internal.example.local?secret=timeout-secret")); - }); - }); - }); - vi.stubGlobal("fetch", fetchMock); - - const request = createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute({ - boardId: fixture.boardId, - itemId: fixture.itemId, - definitionId: fixture.definitionId, - }); - await started.promise; - await vi.advanceTimersByTimeAsync(10_000); - - const result = await request; - expect(result).toEqual({ success: false, errorCode: "REQUEST_FAILED", responseInfo: null }); - expect(JSON.stringify(result)).not.toMatch(/timeout-secret|internal\.example\.local/); - }); - - it("bounds action responses before reporting success", async () => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response("x".repeat(2 * 1024 * 1024 + 1)))); - - await expect( - createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])).execute({ - boardId: fixture.boardId, - itemId: fixture.itemId, - definitionId: fixture.definitionId, - }), - ).resolves.toEqual({ success: false, errorCode: "REQUEST_FAILED", responseInfo: null }); - }); - - it("binds data requests to a viewable item and never exposes backend error text", async () => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - await db - .update(customWidgetDefinitions) - .set({ - displayType: "singleValue", - method: "GET", - displayConfig: stringify({ type: "singleValue", jsonPath: "$.value" }), - }) - .where(eq(customWidgetDefinitions.id, fixture.definitionId)); - vi.stubGlobal( - "fetch", - vi.fn().mockRejectedValue(new Error("Backend http://private.example.local/path?token=super-secret\nstack trace")), - ); - - const input = { - boardId: fixture.boardId, - itemId: fixture.itemId, - definitionId: fixture.definitionId, - }; - const error = await createCustomApiCaller(db, createSession(fixture.viewerId)) - .getData(input) - .catch((caught: unknown) => caught); - expect(error).toMatchObject({ code: "INTERNAL_SERVER_ERROR", message: "Custom API request failed" }); - expect(JSON.stringify(error)).not.toMatch(/super-secret|private\.example\.local|stack trace/); - - await expect(createCustomApiCaller(db, createSession(fixture.unrelatedId)).getData(input)).rejects.toMatchObject({ - code: "NOT_FOUND", - }); - await expect( - createCustomApiCaller(db, createSession(fixture.viewerId)).getData({ ...input, definitionId: createId() }), - ).rejects.toMatchObject({ code: "NOT_FOUND" }); - }); - - it("bounds and disposes non-success data responses", async () => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - await db - .update(customWidgetDefinitions) - .set({ - displayType: "singleValue", - method: "GET", - displayConfig: stringify({ type: "singleValue", jsonPath: "$.value" }), - }) - .where(eq(customWidgetDefinitions.id, fixture.definitionId)); - vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response("x".repeat(2 * 1024 * 1024 + 1), { status: 502 }))); - - const error = await createCustomApiCaller(db, createSession(fixture.viewerId)) - .getData({ - boardId: fixture.boardId, - itemId: fixture.itemId, - definitionId: fixture.definitionId, - }) - .catch((caught: unknown) => caught); - - expect(error).toMatchObject({ code: "INTERNAL_SERVER_ERROR", message: "Custom API request failed" }); - expect(JSON.stringify(error)).not.toContain("x".repeat(100)); - }); - - it("redacts unsafe preview failures and rejects redirects", async () => { - const db = createDb(); - const fixture = await createFixtureAsync(db); - const fetchMock = vi.fn().mockRejectedValue(new Error("redirected to http://private.local?secret=value")); - vi.stubGlobal("fetch", fetchMock); - const caller = createCustomWidgetCaller(db, createSession(fixture.adminId, ["admin"])); - - const result = await caller.preview({ - url: "https://api.example.com/data", - method: "GET", - authType: "none", - displayType: "singleValue", - displayConfig: { type: "singleValue", jsonPath: "$.value", label: "Value", unit: "" }, - secrets: [], - }); - expect(fetchMock).toHaveBeenCalledWith( - "https://api.example.com/data", - expect.objectContaining({ redirect: "error" }), - ); - expect(result).toEqual({ - success: false, - error: "Custom API preview failed", - responseInfo: null, - rawResponse: null, - }); - expect(JSON.stringify(result)).not.toMatch(/private\.local|secret=value/); - }); -}); diff --git a/packages/api/src/router/widgets/downloads.ts b/packages/api/src/router/widgets/downloads.ts index bdce2473f..261d3ba46 100644 --- a/packages/api/src/router/widgets/downloads.ts +++ b/packages/api/src/router/widgets/downloads.ts @@ -1,17 +1,47 @@ import { z } from "zod/v4"; +import type { IntegrationKindByCategory } from "@homarr/definitions"; import { getIntegrationKindsByCategory } from "@homarr/definitions"; +import type { DownloadClientJobsAndStatus } from "@homarr/integrations"; import { createIntegrationAsync, downloadClientItemSchema } from "@homarr/integrations"; import { downloadClientRequestHandler } from "@homarr/request-handler/downloads"; import type { IntegrationAction } from "../../middlewares/integration"; import { createManyIntegrationMiddleware } from "../../middlewares/integration"; -import { settleIntegrationQueries } from "../../settle-integrations"; +import { PUBLIC_INTEGRATION_ERROR, settleIntegrationQueries } from "../../settle-integrations"; import { createTRPCRouter, protectedProcedure, publicProcedure } from "../../trpc"; const createDownloadClientIntegrationMiddleware = (action: IntegrationAction) => createManyIntegrationMiddleware(action, ...getIntegrationKindsByCategory("downloadClient")); +interface DownloadClientQueryResultBase { + integrationId: string; + integrationName: string; +} + +type DownloadClientQueryResult = DownloadClientQueryResultBase & + ( + | { + integration: { + id: string; + name: string; + kind: IntegrationKindByCategory<"downloadClient">; + updatedAt: Date; + }; + data: DownloadClientJobsAndStatus; + error?: never; + } + | { + integration: { + id: string; + name: string; + kind: IntegrationKindByCategory<"downloadClient">; + }; + data: null; + error: string; + } + ); + export const downloadsRouter = createTRPCRouter({ getJobsAndStatuses: publicProcedure .meta({ @@ -24,14 +54,29 @@ export const downloadsRouter = createTRPCRouter({ .concat(createDownloadClientIntegrationMiddleware("query")) .input(z.object({ limitPerIntegration: z.number().default(50) })) .query(async ({ ctx, input }) => { - return await settleIntegrationQueries(ctx.integrations, async (integration) => { - const innerHandler = downloadClientRequestHandler.handler(integration, { limit: input.limitPerIntegration }); - const { data, timestamp } = await innerHandler.getDataAsync(); - return { - integration: { id: integration.id, name: integration.name, kind: integration.kind, updatedAt: timestamp }, - data, - }; - }); + return await settleIntegrationQueries<(typeof ctx.integrations)[number], DownloadClientQueryResult>( + ctx.integrations, + async (integration) => { + const innerHandler = downloadClientRequestHandler.handler(integration, { limit: input.limitPerIntegration }); + const { data, timestamp } = await innerHandler.getDataAsync(); + return { + integrationId: integration.id, + integrationName: integration.name, + integration: { id: integration.id, name: integration.name, kind: integration.kind, updatedAt: timestamp }, + data, + }; + }, + { + fallback: (integration) => ({ + integrationId: integration.id, + integrationName: integration.name, + integration: { id: integration.id, name: integration.name, kind: integration.kind }, + data: null, + error: PUBLIC_INTEGRATION_ERROR, + }), + throwOnAllFailures: true, + }, + ); }), pause: protectedProcedure .meta({ diff --git a/packages/api/src/router/widgets/health-monitoring.ts b/packages/api/src/router/widgets/health-monitoring.ts index 1957f459c..5c123ecb1 100644 --- a/packages/api/src/router/widgets/health-monitoring.ts +++ b/packages/api/src/router/widgets/health-monitoring.ts @@ -1,9 +1,10 @@ import { createIntegrationAsync } from "@homarr/integrations"; +import type { SystemHealthMonitoring } from "@homarr/integrations"; import { SynologyIntegration } from "@homarr/integrations"; import { clusterInfoRequestHandler, systemInfoRequestHandler } from "@homarr/request-handler/health-monitoring"; import { createManyIntegrationMiddleware, createOneIntegrationMiddleware } from "../../middlewares/integration"; -import { settleIntegrationQueries } from "../../settle-integrations"; +import { PUBLIC_INTEGRATION_ERROR, settleIntegrationQueries } from "../../settle-integrations"; import { createTRPCRouter, publicProcedure } from "../../trpc"; const healthMonitoringIntegrationKinds = [ @@ -16,6 +17,14 @@ const healthMonitoringIntegrationKinds = [ "mock", ] as const; +interface SystemHealthQueryResult { + integrationId: string; + integrationName: string; + healthInfo: SystemHealthMonitoring | null; + updatedAt?: Date; + error?: string; +} + export const healthMonitoringRouter = createTRPCRouter({ getSystemHealthStatus: publicProcedure .meta({ @@ -27,15 +36,27 @@ export const healthMonitoringRouter = createTRPCRouter({ }) .concat(createManyIntegrationMiddleware("query", ...healthMonitoringIntegrationKinds)) .query(async ({ ctx }) => { - return await settleIntegrationQueries(ctx.integrations, async (integration) => { - const { data, timestamp } = await systemInfoRequestHandler.handler(integration, {}).getDataAsync(); - return { - integrationId: integration.id, - integrationName: integration.name, - healthInfo: data, - updatedAt: timestamp, - }; - }); + return await settleIntegrationQueries<(typeof ctx.integrations)[number], SystemHealthQueryResult>( + ctx.integrations, + async (integration) => { + const { data, timestamp } = await systemInfoRequestHandler.handler(integration, {}).getDataAsync(); + return { + integrationId: integration.id, + integrationName: integration.name, + healthInfo: data, + updatedAt: timestamp, + }; + }, + { + fallback: (integration) => ({ + integrationId: integration.id, + integrationName: integration.name, + healthInfo: null, + error: PUBLIC_INTEGRATION_ERROR, + }), + throwOnAllFailures: true, + }, + ); }), listStorageVolumes: publicProcedure .meta({ diff --git a/packages/api/src/router/widgets/media-release.ts b/packages/api/src/router/widgets/media-release.ts index f05a46142..e1acb95b6 100644 --- a/packages/api/src/router/widgets/media-release.ts +++ b/packages/api/src/router/widgets/media-release.ts @@ -2,32 +2,21 @@ import { getIntegrationKindsByCategory } from "@homarr/definitions"; import { mediaReleaseRequestHandler } from "@homarr/request-handler/media-release"; import { createManyIntegrationMiddleware } from "../../middlewares/integration"; -import { settleIntegrationQueries } from "../../settle-integrations"; import { createTRPCRouter, publicProcedure } from "../../trpc"; +import { getMediaReleaseResponse } from "./media-release-result"; export const mediaReleaseRouter = createTRPCRouter({ getMediaReleases: publicProcedure .concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("mediaRelease"))) .query(async ({ ctx }) => { - const results = await settleIntegrationQueries(ctx.integrations, async (integration) => { + return await getMediaReleaseResponse(ctx.integrations, async (integration) => { const innerHandler = mediaReleaseRequestHandler.handler(integration, {}); const { data, timestamp } = await innerHandler.getDataAsync(); return { - integration: { - id: integration.id, - name: integration.name, - kind: integration.kind, - updatedAt: timestamp, - }, releases: data, + updatedAt: timestamp, }; }); - return results.flatMap((result) => - result.releases.map((release) => ({ - ...release, - integration: result.integration, - })), - ); }), }); diff --git a/packages/api/src/router/widgets/rssFeed.ts b/packages/api/src/router/widgets/rssFeed.ts index 5894dd8ac..87c49fca0 100644 --- a/packages/api/src/router/widgets/rssFeed.ts +++ b/packages/api/src/router/widgets/rssFeed.ts @@ -32,7 +32,7 @@ const feedsInput = z.object({ export const rssFeedRouter = createTRPCRouter({ getFeeds: publicProcedure.input(feedsInput).query(async ({ ctx, input }) => { - if (env.NO_EXTERNAL_CONNECTION) return []; + if (env.NO_EXTERNAL_CONNECTION) return { entries: [], failedFeedCount: 0 }; const urls = (await canAccessAllFeedsAsync(ctx.db, ctx.session)) ? input.urls diff --git a/packages/api/src/router/widgets/uptime-kuma.ts b/packages/api/src/router/widgets/uptime-kuma.ts index 6df14090c..e3082c284 100644 --- a/packages/api/src/router/widgets/uptime-kuma.ts +++ b/packages/api/src/router/widgets/uptime-kuma.ts @@ -1,24 +1,39 @@ import { uptimeKumaRequestHandler } from "@homarr/request-handler/uptime-kuma"; import { createManyIntegrationMiddleware } from "../../middlewares/integration"; -import { settleIntegrationQueries } from "../../settle-integrations"; +import { settleIntegrationQueries, toPublicIntegrationError } from "../../settle-integrations"; import { createTRPCRouter, publicProcedure } from "../../trpc"; export const uptimeKumaRouter = createTRPCRouter({ getDashboard: publicProcedure .concat(createManyIntegrationMiddleware("query", "uptimeKuma")) .query(async ({ ctx }) => { - return await settleIntegrationQueries(ctx.integrations, async (integration) => { - const innerHandler = uptimeKumaRequestHandler.handler(integration, {}); - const { data, timestamp } = await innerHandler.getDataAsync(); + return await settleIntegrationQueries( + ctx.integrations, + async (integration) => { + const innerHandler = uptimeKumaRequestHandler.handler(integration, {}); + const { data, timestamp } = await innerHandler.getDataAsync(); - return { - integrationId: integration.id, - integrationName: integration.name, - integrationUrl: integration.url, - dashboard: data, - updatedAt: timestamp, - }; - }); + return { + integrationId: integration.id, + integrationName: integration.name, + integrationUrl: integration.url, + dashboard: data as typeof data | null, + updatedAt: timestamp, + error: undefined as string | undefined, + }; + }, + { + fallback: (integration, error) => ({ + integrationId: integration.id, + integrationName: integration.name, + integrationUrl: integration.url, + dashboard: null, + updatedAt: new Date(0), + error: toPublicIntegrationError(error), + }), + throwOnAllFailures: true, + }, + ); }), }); diff --git a/packages/boards/src/layout-selection.ts b/packages/boards/src/layout-selection.ts index 20503188f..ec6a87f04 100644 --- a/packages/boards/src/layout-selection.ts +++ b/packages/boards/src/layout-selection.ts @@ -5,10 +5,7 @@ interface ResponsiveLayout { breakpoint: number; } -export const getLayoutIdForViewportWidth = ( - layouts: readonly ResponsiveLayout[], - viewportWidth: number, -): string => { +export const getLayoutIdForViewportWidth = (layouts: readonly ResponsiveLayout[], viewportWidth: number): string => { if (layouts.length === 0) { throw new Error("Expected the board to contain a layout"); } diff --git a/packages/db/migrations/mysql/0045_add_assistant_web_search.sql b/packages/db/migrations/mysql/0045_add_assistant_web_search.sql deleted file mode 100644 index 2d586421f..000000000 --- a/packages/db/migrations/mysql/0045_add_assistant_web_search.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `assistant_configuration` ADD `web_search_enabled` boolean DEFAULT false NOT NULL; diff --git a/packages/db/migrations/mysql/meta/0038_snapshot.json b/packages/db/migrations/mysql/meta/0038_snapshot.json index 7f82bd39b..0840b2436 100644 --- a/packages/db/migrations/mysql/meta/0038_snapshot.json +++ b/packages/db/migrations/mysql/meta/0038_snapshot.json @@ -88,9 +88,7 @@ "indexes": { "userId_idx": { "name": "userId_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -99,12 +97,8 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -112,10 +106,7 @@ "compositePrimaryKeys": { "account_provider_provider_account_id_pk": { "name": "account_provider_provider_account_id_pk", - "columns": [ - "provider", - "provider_account_id" - ] + "columns": ["provider", "provider_account_id"] } }, "uniqueConstraints": {}, @@ -152,12 +143,8 @@ "name": "apiKey_user_id_user_id_fk", "tableFrom": "apiKey", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -165,9 +152,7 @@ "compositePrimaryKeys": { "apiKey_id": { "name": "apiKey_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -224,9 +209,7 @@ "compositePrimaryKeys": { "app_id": { "name": "app_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -263,12 +246,8 @@ "name": "boardGroupPermission_board_id_board_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -276,12 +255,8 @@ "name": "boardGroupPermission_group_id_group_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -289,11 +264,7 @@ "compositePrimaryKeys": { "boardGroupPermission_board_id_group_id_permission_pk": { "name": "boardGroupPermission_board_id_group_id_permission_pk", - "columns": [ - "board_id", - "group_id", - "permission" - ] + "columns": ["board_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -330,12 +301,8 @@ "name": "boardUserPermission_board_id_board_id_fk", "tableFrom": "boardUserPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -343,12 +310,8 @@ "name": "boardUserPermission_user_id_user_id_fk", "tableFrom": "boardUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -356,11 +319,7 @@ "compositePrimaryKeys": { "boardUserPermission_board_id_user_id_permission_pk": { "name": "boardUserPermission_board_id_user_id_permission_pk", - "columns": [ - "board_id", - "user_id", - "permission" - ] + "columns": ["board_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -518,12 +477,8 @@ "name": "board_creator_id_user_id_fk", "tableFrom": "board", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -531,17 +486,13 @@ "compositePrimaryKeys": { "board_id": { "name": "board_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "board_name_unique": { "name": "board_name_unique", - "columns": [ - "name" - ] + "columns": ["name"] } }, "checkConstraint": {} @@ -577,9 +528,7 @@ "compositePrimaryKeys": { "cron_job_configuration_name": { "name": "cron_job_configuration_name", - "columns": [ - "name" - ] + "columns": ["name"] } }, "uniqueConstraints": {}, @@ -609,12 +558,8 @@ "name": "groupMember_group_id_group_id_fk", "tableFrom": "groupMember", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -622,12 +567,8 @@ "name": "groupMember_user_id_user_id_fk", "tableFrom": "groupMember", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -635,10 +576,7 @@ "compositePrimaryKeys": { "groupMember_group_id_user_id_pk": { "name": "groupMember_group_id_user_id_pk", - "columns": [ - "group_id", - "user_id" - ] + "columns": ["group_id", "user_id"] } }, "uniqueConstraints": {}, @@ -668,12 +606,8 @@ "name": "groupPermission_group_id_group_id_fk", "tableFrom": "groupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -734,12 +668,8 @@ "name": "group_owner_id_user_id_fk", "tableFrom": "group", "tableTo": "user", - "columnsFrom": [ - "owner_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -747,12 +677,8 @@ "name": "group_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -760,12 +686,8 @@ "name": "group_mobile_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -773,17 +695,13 @@ "compositePrimaryKeys": { "group_id": { "name": "group_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "group_name_unique": { "name": "group_name_unique", - "columns": [ - "name" - ] + "columns": ["name"] } }, "checkConstraint": {} @@ -811,9 +729,7 @@ "compositePrimaryKeys": { "iconRepository_id": { "name": "iconRepository_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -864,12 +780,8 @@ "name": "icon_icon_repository_id_iconRepository_id_fk", "tableFrom": "icon", "tableTo": "iconRepository", - "columnsFrom": [ - "icon_repository_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -877,9 +789,7 @@ "compositePrimaryKeys": { "icon_id": { "name": "icon_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -916,12 +826,8 @@ "name": "integrationGroupPermissions_integration_id_integration_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -929,12 +835,8 @@ "name": "integrationGroupPermissions_group_id_group_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -942,11 +844,7 @@ "compositePrimaryKeys": { "integration_group_permission__pk": { "name": "integration_group_permission__pk", - "columns": [ - "integration_id", - "group_id", - "permission" - ] + "columns": ["integration_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -976,12 +874,8 @@ "name": "integration_item_item_id_item_id_fk", "tableFrom": "integration_item", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -989,12 +883,8 @@ "name": "integration_item_integration_id_integration_id_fk", "tableFrom": "integration_item", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1002,10 +892,7 @@ "compositePrimaryKeys": { "integration_item_item_id_integration_id_pk": { "name": "integration_item_item_id_integration_id_pk", - "columns": [ - "item_id", - "integration_id" - ] + "columns": ["item_id", "integration_id"] } }, "uniqueConstraints": {}, @@ -1046,16 +933,12 @@ "indexes": { "integration_secret__kind_idx": { "name": "integration_secret__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false }, "integration_secret__updated_at_idx": { "name": "integration_secret__updated_at_idx", - "columns": [ - "updated_at" - ], + "columns": ["updated_at"], "isUnique": false } }, @@ -1064,12 +947,8 @@ "name": "integrationSecret_integration_id_integration_id_fk", "tableFrom": "integrationSecret", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1077,10 +956,7 @@ "compositePrimaryKeys": { "integrationSecret_integration_id_kind_pk": { "name": "integrationSecret_integration_id_kind_pk", - "columns": [ - "integration_id", - "kind" - ] + "columns": ["integration_id", "kind"] } }, "uniqueConstraints": {}, @@ -1117,12 +993,8 @@ "name": "integrationUserPermission_integration_id_integration_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1130,12 +1002,8 @@ "name": "integrationUserPermission_user_id_user_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1143,11 +1011,7 @@ "compositePrimaryKeys": { "integrationUserPermission_integration_id_user_id_permission_pk": { "name": "integrationUserPermission_integration_id_user_id_permission_pk", - "columns": [ - "integration_id", - "user_id", - "permission" - ] + "columns": ["integration_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -1195,9 +1059,7 @@ "indexes": { "integration__kind_idx": { "name": "integration__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false } }, @@ -1206,12 +1068,8 @@ "name": "integration_app_id_app_id_fk", "tableFrom": "integration", "tableTo": "app", - "columnsFrom": [ - "app_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["app_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1219,9 +1077,7 @@ "compositePrimaryKeys": { "integration_id": { "name": "integration_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1265,12 +1121,8 @@ "name": "invite_creator_id_user_id_fk", "tableFrom": "invite", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1278,17 +1130,13 @@ "compositePrimaryKeys": { "invite_id": { "name": "invite_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "invite_token_unique": { "name": "invite_token_unique", - "columns": [ - "token" - ] + "columns": ["token"] } }, "checkConstraint": {} @@ -1352,12 +1200,8 @@ "name": "item_layout_item_id_item_id_fk", "tableFrom": "item_layout", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1365,12 +1209,8 @@ "name": "item_layout_section_id_section_id_fk", "tableFrom": "item_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1378,12 +1218,8 @@ "name": "item_layout_layout_id_layout_id_fk", "tableFrom": "item_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1391,11 +1227,7 @@ "compositePrimaryKeys": { "item_layout_item_id_section_id_layout_id_pk": { "name": "item_layout_item_id_section_id_layout_id_pk", - "columns": [ - "item_id", - "section_id", - "layout_id" - ] + "columns": ["item_id", "section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -1448,12 +1280,8 @@ "name": "item_board_id_board_id_fk", "tableFrom": "item", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1461,9 +1289,7 @@ "compositePrimaryKeys": { "item_id": { "name": "item_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1515,12 +1341,8 @@ "name": "layout_board_id_board_id_fk", "tableFrom": "layout", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1528,9 +1350,7 @@ "compositePrimaryKeys": { "layout_id": { "name": "layout_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1596,12 +1416,8 @@ "name": "media_creator_id_user_id_fk", "tableFrom": "media", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1609,9 +1425,7 @@ "compositePrimaryKeys": { "media_id": { "name": "media_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1647,9 +1461,7 @@ "compositePrimaryKeys": { "onboarding_id": { "name": "onboarding_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1722,12 +1534,8 @@ "name": "search_engine_integration_id_integration_id_fk", "tableFrom": "search_engine", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1735,17 +1543,13 @@ "compositePrimaryKeys": { "search_engine_id": { "name": "search_engine_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "search_engine_short_unique": { "name": "search_engine_short_unique", - "columns": [ - "short" - ] + "columns": ["short"] } }, "checkConstraint": {} @@ -1782,12 +1586,8 @@ "name": "section_collapse_state_user_id_user_id_fk", "tableFrom": "section_collapse_state", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1795,12 +1595,8 @@ "name": "section_collapse_state_section_id_section_id_fk", "tableFrom": "section_collapse_state", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1808,10 +1604,7 @@ "compositePrimaryKeys": { "section_collapse_state_user_id_section_id_pk": { "name": "section_collapse_state_user_id_section_id_pk", - "columns": [ - "user_id", - "section_id" - ] + "columns": ["user_id", "section_id"] } }, "uniqueConstraints": {}, @@ -1876,12 +1669,8 @@ "name": "section_layout_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1889,12 +1678,8 @@ "name": "section_layout_layout_id_layout_id_fk", "tableFrom": "section_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1902,12 +1687,8 @@ "name": "section_layout_parent_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "parent_section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1915,10 +1696,7 @@ "compositePrimaryKeys": { "section_layout_section_id_layout_id_pk": { "name": "section_layout_section_id_layout_id_pk", - "columns": [ - "section_id", - "layout_id" - ] + "columns": ["section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -1984,12 +1762,8 @@ "name": "section_board_id_board_id_fk", "tableFrom": "section", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1997,9 +1771,7 @@ "compositePrimaryKeys": { "section_id": { "name": "section_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -2029,17 +1801,13 @@ "compositePrimaryKeys": { "serverSetting_setting_key": { "name": "serverSetting_setting_key", - "columns": [ - "setting_key" - ] + "columns": ["setting_key"] } }, "uniqueConstraints": { "serverSetting_settingKey_unique": { "name": "serverSetting_settingKey_unique", - "columns": [ - "setting_key" - ] + "columns": ["setting_key"] } }, "checkConstraint": {} @@ -2072,9 +1840,7 @@ "indexes": { "user_id_idx": { "name": "user_id_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -2083,12 +1849,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2096,9 +1858,7 @@ "compositePrimaryKeys": { "session_session_token": { "name": "session_session_token", - "columns": [ - "session_token" - ] + "columns": ["session_token"] } }, "uniqueConstraints": {}, @@ -2225,12 +1985,8 @@ "name": "user_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2238,12 +1994,8 @@ "name": "user_mobile_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2251,12 +2003,8 @@ "name": "user_default_search_engine_id_search_engine_id_fk", "tableFrom": "user", "tableTo": "search_engine", - "columnsFrom": [ - "default_search_engine_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2264,9 +2012,7 @@ "compositePrimaryKeys": { "user_id": { "name": "user_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -2302,10 +2048,7 @@ "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { "name": "verificationToken_identifier_token_pk", - "columns": [ - "identifier", - "token" - ] + "columns": ["identifier", "token"] } }, "uniqueConstraints": {}, @@ -2341,10 +2084,7 @@ "compositePrimaryKeys": { "trusted_certificate_hostname_hostname_thumbprint_pk": { "name": "trusted_certificate_hostname_hostname_thumbprint_pk", - "columns": [ - "hostname", - "thumbprint" - ] + "columns": ["hostname", "thumbprint"] } }, "uniqueConstraints": {}, @@ -2361,4 +2101,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/db/migrations/mysql/meta/0040_snapshot.json b/packages/db/migrations/mysql/meta/0040_snapshot.json index 63c597c46..a6b956765 100644 --- a/packages/db/migrations/mysql/meta/0040_snapshot.json +++ b/packages/db/migrations/mysql/meta/0040_snapshot.json @@ -88,9 +88,7 @@ "indexes": { "userId_idx": { "name": "userId_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -99,12 +97,8 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -112,10 +106,7 @@ "compositePrimaryKeys": { "account_provider_provider_account_id_pk": { "name": "account_provider_provider_account_id_pk", - "columns": [ - "provider", - "provider_account_id" - ] + "columns": ["provider", "provider_account_id"] } }, "uniqueConstraints": {}, @@ -152,12 +143,8 @@ "name": "apiKey_user_id_user_id_fk", "tableFrom": "apiKey", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -165,9 +152,7 @@ "compositePrimaryKeys": { "apiKey_id": { "name": "apiKey_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -224,9 +209,7 @@ "compositePrimaryKeys": { "app_id": { "name": "app_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -263,12 +246,8 @@ "name": "boardGroupPermission_board_id_board_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -276,12 +255,8 @@ "name": "boardGroupPermission_group_id_group_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -289,11 +264,7 @@ "compositePrimaryKeys": { "boardGroupPermission_board_id_group_id_permission_pk": { "name": "boardGroupPermission_board_id_group_id_permission_pk", - "columns": [ - "board_id", - "group_id", - "permission" - ] + "columns": ["board_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -330,12 +301,8 @@ "name": "boardUserPermission_board_id_board_id_fk", "tableFrom": "boardUserPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -343,12 +310,8 @@ "name": "boardUserPermission_user_id_user_id_fk", "tableFrom": "boardUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -356,11 +319,7 @@ "compositePrimaryKeys": { "boardUserPermission_board_id_user_id_permission_pk": { "name": "boardUserPermission_board_id_user_id_permission_pk", - "columns": [ - "board_id", - "user_id", - "permission" - ] + "columns": ["board_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -518,12 +477,8 @@ "name": "board_creator_id_user_id_fk", "tableFrom": "board", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -531,17 +486,13 @@ "compositePrimaryKeys": { "board_id": { "name": "board_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "board_name_unique": { "name": "board_name_unique", - "columns": [ - "name" - ] + "columns": ["name"] } }, "checkConstraint": {} @@ -577,9 +528,7 @@ "compositePrimaryKeys": { "cron_job_configuration_name": { "name": "cron_job_configuration_name", - "columns": [ - "name" - ] + "columns": ["name"] } }, "uniqueConstraints": {}, @@ -706,12 +655,8 @@ "name": "custom_widget_definition_creator_id_user_id_fk", "tableFrom": "custom_widget_definition", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -719,9 +664,7 @@ "compositePrimaryKeys": { "custom_widget_definition_id": { "name": "custom_widget_definition_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -765,12 +708,8 @@ "name": "cw_secret_definition_id_cw_definition_id_fk", "tableFrom": "custom_widget_secret", "tableTo": "custom_widget_definition", - "columnsFrom": [ - "definition_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -778,10 +717,7 @@ "compositePrimaryKeys": { "custom_widget_secret_definition_id_kind_pk": { "name": "custom_widget_secret_definition_id_kind_pk", - "columns": [ - "definition_id", - "kind" - ] + "columns": ["definition_id", "kind"] } }, "uniqueConstraints": {}, @@ -811,12 +747,8 @@ "name": "groupMember_group_id_group_id_fk", "tableFrom": "groupMember", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -824,12 +756,8 @@ "name": "groupMember_user_id_user_id_fk", "tableFrom": "groupMember", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -837,10 +765,7 @@ "compositePrimaryKeys": { "groupMember_group_id_user_id_pk": { "name": "groupMember_group_id_user_id_pk", - "columns": [ - "group_id", - "user_id" - ] + "columns": ["group_id", "user_id"] } }, "uniqueConstraints": {}, @@ -870,12 +795,8 @@ "name": "groupPermission_group_id_group_id_fk", "tableFrom": "groupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -936,12 +857,8 @@ "name": "group_owner_id_user_id_fk", "tableFrom": "group", "tableTo": "user", - "columnsFrom": [ - "owner_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -949,12 +866,8 @@ "name": "group_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -962,12 +875,8 @@ "name": "group_mobile_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -975,17 +884,13 @@ "compositePrimaryKeys": { "group_id": { "name": "group_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "group_name_unique": { "name": "group_name_unique", - "columns": [ - "name" - ] + "columns": ["name"] } }, "checkConstraint": {} @@ -1013,9 +918,7 @@ "compositePrimaryKeys": { "iconRepository_id": { "name": "iconRepository_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1066,12 +969,8 @@ "name": "icon_icon_repository_id_iconRepository_id_fk", "tableFrom": "icon", "tableTo": "iconRepository", - "columnsFrom": [ - "icon_repository_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1079,9 +978,7 @@ "compositePrimaryKeys": { "icon_id": { "name": "icon_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1118,12 +1015,8 @@ "name": "integrationGroupPermissions_integration_id_integration_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1131,12 +1024,8 @@ "name": "integrationGroupPermissions_group_id_group_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1144,11 +1033,7 @@ "compositePrimaryKeys": { "integration_group_permission__pk": { "name": "integration_group_permission__pk", - "columns": [ - "integration_id", - "group_id", - "permission" - ] + "columns": ["integration_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -1178,12 +1063,8 @@ "name": "integration_item_item_id_item_id_fk", "tableFrom": "integration_item", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1191,12 +1072,8 @@ "name": "integration_item_integration_id_integration_id_fk", "tableFrom": "integration_item", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1204,10 +1081,7 @@ "compositePrimaryKeys": { "integration_item_item_id_integration_id_pk": { "name": "integration_item_item_id_integration_id_pk", - "columns": [ - "item_id", - "integration_id" - ] + "columns": ["item_id", "integration_id"] } }, "uniqueConstraints": {}, @@ -1248,16 +1122,12 @@ "indexes": { "integration_secret__kind_idx": { "name": "integration_secret__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false }, "integration_secret__updated_at_idx": { "name": "integration_secret__updated_at_idx", - "columns": [ - "updated_at" - ], + "columns": ["updated_at"], "isUnique": false } }, @@ -1266,12 +1136,8 @@ "name": "integrationSecret_integration_id_integration_id_fk", "tableFrom": "integrationSecret", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1279,10 +1145,7 @@ "compositePrimaryKeys": { "integrationSecret_integration_id_kind_pk": { "name": "integrationSecret_integration_id_kind_pk", - "columns": [ - "integration_id", - "kind" - ] + "columns": ["integration_id", "kind"] } }, "uniqueConstraints": {}, @@ -1319,12 +1182,8 @@ "name": "integrationUserPermission_integration_id_integration_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1332,12 +1191,8 @@ "name": "integrationUserPermission_user_id_user_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1345,11 +1200,7 @@ "compositePrimaryKeys": { "integrationUserPermission_integration_id_user_id_permission_pk": { "name": "integrationUserPermission_integration_id_user_id_permission_pk", - "columns": [ - "integration_id", - "user_id", - "permission" - ] + "columns": ["integration_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -1397,9 +1248,7 @@ "indexes": { "integration__kind_idx": { "name": "integration__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false } }, @@ -1408,12 +1257,8 @@ "name": "integration_app_id_app_id_fk", "tableFrom": "integration", "tableTo": "app", - "columnsFrom": [ - "app_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["app_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1421,9 +1266,7 @@ "compositePrimaryKeys": { "integration_id": { "name": "integration_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1467,12 +1310,8 @@ "name": "invite_creator_id_user_id_fk", "tableFrom": "invite", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1480,17 +1319,13 @@ "compositePrimaryKeys": { "invite_id": { "name": "invite_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "invite_token_unique": { "name": "invite_token_unique", - "columns": [ - "token" - ] + "columns": ["token"] } }, "checkConstraint": {} @@ -1554,12 +1389,8 @@ "name": "item_layout_item_id_item_id_fk", "tableFrom": "item_layout", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1567,12 +1398,8 @@ "name": "item_layout_section_id_section_id_fk", "tableFrom": "item_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1580,12 +1407,8 @@ "name": "item_layout_layout_id_layout_id_fk", "tableFrom": "item_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1593,11 +1416,7 @@ "compositePrimaryKeys": { "item_layout_item_id_section_id_layout_id_pk": { "name": "item_layout_item_id_section_id_layout_id_pk", - "columns": [ - "item_id", - "section_id", - "layout_id" - ] + "columns": ["item_id", "section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -1650,12 +1469,8 @@ "name": "item_board_id_board_id_fk", "tableFrom": "item", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1663,9 +1478,7 @@ "compositePrimaryKeys": { "item_id": { "name": "item_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1717,12 +1530,8 @@ "name": "layout_board_id_board_id_fk", "tableFrom": "layout", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1730,9 +1539,7 @@ "compositePrimaryKeys": { "layout_id": { "name": "layout_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1798,12 +1605,8 @@ "name": "media_creator_id_user_id_fk", "tableFrom": "media", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1811,9 +1614,7 @@ "compositePrimaryKeys": { "media_id": { "name": "media_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1849,9 +1650,7 @@ "compositePrimaryKeys": { "onboarding_id": { "name": "onboarding_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1924,12 +1723,8 @@ "name": "search_engine_integration_id_integration_id_fk", "tableFrom": "search_engine", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1937,17 +1732,13 @@ "compositePrimaryKeys": { "search_engine_id": { "name": "search_engine_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "search_engine_short_unique": { "name": "search_engine_short_unique", - "columns": [ - "short" - ] + "columns": ["short"] } }, "checkConstraint": {} @@ -1984,12 +1775,8 @@ "name": "section_collapse_state_user_id_user_id_fk", "tableFrom": "section_collapse_state", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1997,12 +1784,8 @@ "name": "section_collapse_state_section_id_section_id_fk", "tableFrom": "section_collapse_state", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2010,10 +1793,7 @@ "compositePrimaryKeys": { "section_collapse_state_user_id_section_id_pk": { "name": "section_collapse_state_user_id_section_id_pk", - "columns": [ - "user_id", - "section_id" - ] + "columns": ["user_id", "section_id"] } }, "uniqueConstraints": {}, @@ -2078,12 +1858,8 @@ "name": "section_layout_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2091,12 +1867,8 @@ "name": "section_layout_layout_id_layout_id_fk", "tableFrom": "section_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2104,12 +1876,8 @@ "name": "section_layout_parent_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "parent_section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2117,10 +1885,7 @@ "compositePrimaryKeys": { "section_layout_section_id_layout_id_pk": { "name": "section_layout_section_id_layout_id_pk", - "columns": [ - "section_id", - "layout_id" - ] + "columns": ["section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -2186,12 +1951,8 @@ "name": "section_board_id_board_id_fk", "tableFrom": "section", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2199,9 +1960,7 @@ "compositePrimaryKeys": { "section_id": { "name": "section_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -2231,17 +1990,13 @@ "compositePrimaryKeys": { "serverSetting_setting_key": { "name": "serverSetting_setting_key", - "columns": [ - "setting_key" - ] + "columns": ["setting_key"] } }, "uniqueConstraints": { "serverSetting_settingKey_unique": { "name": "serverSetting_settingKey_unique", - "columns": [ - "setting_key" - ] + "columns": ["setting_key"] } }, "checkConstraint": {} @@ -2274,9 +2029,7 @@ "indexes": { "user_id_idx": { "name": "user_id_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -2285,12 +2038,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2298,9 +2047,7 @@ "compositePrimaryKeys": { "session_session_token": { "name": "session_session_token", - "columns": [ - "session_token" - ] + "columns": ["session_token"] } }, "uniqueConstraints": {}, @@ -2443,12 +2190,8 @@ "name": "user_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2456,12 +2199,8 @@ "name": "user_mobile_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2469,12 +2208,8 @@ "name": "user_default_search_engine_id_search_engine_id_fk", "tableFrom": "user", "tableTo": "search_engine", - "columnsFrom": [ - "default_search_engine_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2482,9 +2217,7 @@ "compositePrimaryKeys": { "user_id": { "name": "user_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -2520,10 +2253,7 @@ "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { "name": "verificationToken_identifier_token_pk", - "columns": [ - "identifier", - "token" - ] + "columns": ["identifier", "token"] } }, "uniqueConstraints": {}, @@ -2559,10 +2289,7 @@ "compositePrimaryKeys": { "trusted_certificate_hostname_hostname_thumbprint_pk": { "name": "trusted_certificate_hostname_hostname_thumbprint_pk", - "columns": [ - "hostname", - "thumbprint" - ] + "columns": ["hostname", "thumbprint"] } }, "uniqueConstraints": {}, @@ -2579,4 +2306,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/db/migrations/mysql/meta/0041_snapshot.json b/packages/db/migrations/mysql/meta/0041_snapshot.json index 1cbe65bde..75b97db84 100644 --- a/packages/db/migrations/mysql/meta/0041_snapshot.json +++ b/packages/db/migrations/mysql/meta/0041_snapshot.json @@ -88,9 +88,7 @@ "indexes": { "userId_idx": { "name": "userId_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -99,12 +97,8 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -112,10 +106,7 @@ "compositePrimaryKeys": { "account_provider_provider_account_id_pk": { "name": "account_provider_provider_account_id_pk", - "columns": [ - "provider", - "provider_account_id" - ] + "columns": ["provider", "provider_account_id"] } }, "uniqueConstraints": {}, @@ -152,12 +143,8 @@ "name": "apiKey_user_id_user_id_fk", "tableFrom": "apiKey", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -165,9 +152,7 @@ "compositePrimaryKeys": { "apiKey_id": { "name": "apiKey_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -224,9 +209,7 @@ "compositePrimaryKeys": { "app_id": { "name": "app_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -263,12 +246,8 @@ "name": "boardGroupPermission_board_id_board_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -276,12 +255,8 @@ "name": "boardGroupPermission_group_id_group_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -289,11 +264,7 @@ "compositePrimaryKeys": { "boardGroupPermission_board_id_group_id_permission_pk": { "name": "boardGroupPermission_board_id_group_id_permission_pk", - "columns": [ - "board_id", - "group_id", - "permission" - ] + "columns": ["board_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -330,12 +301,8 @@ "name": "boardUserPermission_board_id_board_id_fk", "tableFrom": "boardUserPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -343,12 +310,8 @@ "name": "boardUserPermission_user_id_user_id_fk", "tableFrom": "boardUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -356,11 +319,7 @@ "compositePrimaryKeys": { "boardUserPermission_board_id_user_id_permission_pk": { "name": "boardUserPermission_board_id_user_id_permission_pk", - "columns": [ - "board_id", - "user_id", - "permission" - ] + "columns": ["board_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -518,12 +477,8 @@ "name": "board_creator_id_user_id_fk", "tableFrom": "board", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -531,17 +486,13 @@ "compositePrimaryKeys": { "board_id": { "name": "board_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "board_name_unique": { "name": "board_name_unique", - "columns": [ - "name" - ] + "columns": ["name"] } }, "checkConstraint": {} @@ -577,9 +528,7 @@ "compositePrimaryKeys": { "cron_job_configuration_name": { "name": "cron_job_configuration_name", - "columns": [ - "name" - ] + "columns": ["name"] } }, "uniqueConstraints": {}, @@ -707,12 +656,8 @@ "name": "custom_widget_definition_creator_id_user_id_fk", "tableFrom": "custom_widget_definition", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -720,9 +665,7 @@ "compositePrimaryKeys": { "custom_widget_definition_id": { "name": "custom_widget_definition_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -766,12 +709,8 @@ "name": "cw_secret_definition_id_cw_definition_id_fk", "tableFrom": "custom_widget_secret", "tableTo": "custom_widget_definition", - "columnsFrom": [ - "definition_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -779,10 +718,7 @@ "compositePrimaryKeys": { "custom_widget_secret_definition_id_kind_pk": { "name": "custom_widget_secret_definition_id_kind_pk", - "columns": [ - "definition_id", - "kind" - ] + "columns": ["definition_id", "kind"] } }, "uniqueConstraints": {}, @@ -812,12 +748,8 @@ "name": "groupMember_group_id_group_id_fk", "tableFrom": "groupMember", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -825,12 +757,8 @@ "name": "groupMember_user_id_user_id_fk", "tableFrom": "groupMember", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -838,10 +766,7 @@ "compositePrimaryKeys": { "groupMember_group_id_user_id_pk": { "name": "groupMember_group_id_user_id_pk", - "columns": [ - "group_id", - "user_id" - ] + "columns": ["group_id", "user_id"] } }, "uniqueConstraints": {}, @@ -871,12 +796,8 @@ "name": "groupPermission_group_id_group_id_fk", "tableFrom": "groupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -937,12 +858,8 @@ "name": "group_owner_id_user_id_fk", "tableFrom": "group", "tableTo": "user", - "columnsFrom": [ - "owner_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -950,12 +867,8 @@ "name": "group_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -963,12 +876,8 @@ "name": "group_mobile_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -976,17 +885,13 @@ "compositePrimaryKeys": { "group_id": { "name": "group_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "group_name_unique": { "name": "group_name_unique", - "columns": [ - "name" - ] + "columns": ["name"] } }, "checkConstraint": {} @@ -1014,9 +919,7 @@ "compositePrimaryKeys": { "iconRepository_id": { "name": "iconRepository_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1067,12 +970,8 @@ "name": "icon_icon_repository_id_iconRepository_id_fk", "tableFrom": "icon", "tableTo": "iconRepository", - "columnsFrom": [ - "icon_repository_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1080,9 +979,7 @@ "compositePrimaryKeys": { "icon_id": { "name": "icon_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1119,12 +1016,8 @@ "name": "integrationGroupPermissions_integration_id_integration_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1132,12 +1025,8 @@ "name": "integrationGroupPermissions_group_id_group_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1145,11 +1034,7 @@ "compositePrimaryKeys": { "integration_group_permission__pk": { "name": "integration_group_permission__pk", - "columns": [ - "integration_id", - "group_id", - "permission" - ] + "columns": ["integration_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -1179,12 +1064,8 @@ "name": "integration_item_item_id_item_id_fk", "tableFrom": "integration_item", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1192,12 +1073,8 @@ "name": "integration_item_integration_id_integration_id_fk", "tableFrom": "integration_item", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1205,10 +1082,7 @@ "compositePrimaryKeys": { "integration_item_item_id_integration_id_pk": { "name": "integration_item_item_id_integration_id_pk", - "columns": [ - "item_id", - "integration_id" - ] + "columns": ["item_id", "integration_id"] } }, "uniqueConstraints": {}, @@ -1249,16 +1123,12 @@ "indexes": { "integration_secret__kind_idx": { "name": "integration_secret__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false }, "integration_secret__updated_at_idx": { "name": "integration_secret__updated_at_idx", - "columns": [ - "updated_at" - ], + "columns": ["updated_at"], "isUnique": false } }, @@ -1267,12 +1137,8 @@ "name": "integrationSecret_integration_id_integration_id_fk", "tableFrom": "integrationSecret", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1280,10 +1146,7 @@ "compositePrimaryKeys": { "integrationSecret_integration_id_kind_pk": { "name": "integrationSecret_integration_id_kind_pk", - "columns": [ - "integration_id", - "kind" - ] + "columns": ["integration_id", "kind"] } }, "uniqueConstraints": {}, @@ -1320,12 +1183,8 @@ "name": "integrationUserPermission_integration_id_integration_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1333,12 +1192,8 @@ "name": "integrationUserPermission_user_id_user_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1346,11 +1201,7 @@ "compositePrimaryKeys": { "integrationUserPermission_integration_id_user_id_permission_pk": { "name": "integrationUserPermission_integration_id_user_id_permission_pk", - "columns": [ - "integration_id", - "user_id", - "permission" - ] + "columns": ["integration_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -1398,9 +1249,7 @@ "indexes": { "integration__kind_idx": { "name": "integration__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false } }, @@ -1409,12 +1258,8 @@ "name": "integration_app_id_app_id_fk", "tableFrom": "integration", "tableTo": "app", - "columnsFrom": [ - "app_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["app_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1422,9 +1267,7 @@ "compositePrimaryKeys": { "integration_id": { "name": "integration_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1468,12 +1311,8 @@ "name": "invite_creator_id_user_id_fk", "tableFrom": "invite", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1481,17 +1320,13 @@ "compositePrimaryKeys": { "invite_id": { "name": "invite_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "invite_token_unique": { "name": "invite_token_unique", - "columns": [ - "token" - ] + "columns": ["token"] } }, "checkConstraint": {} @@ -1555,12 +1390,8 @@ "name": "item_layout_item_id_item_id_fk", "tableFrom": "item_layout", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1568,12 +1399,8 @@ "name": "item_layout_section_id_section_id_fk", "tableFrom": "item_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1581,12 +1408,8 @@ "name": "item_layout_layout_id_layout_id_fk", "tableFrom": "item_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1594,11 +1417,7 @@ "compositePrimaryKeys": { "item_layout_item_id_section_id_layout_id_pk": { "name": "item_layout_item_id_section_id_layout_id_pk", - "columns": [ - "item_id", - "section_id", - "layout_id" - ] + "columns": ["item_id", "section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -1651,12 +1470,8 @@ "name": "item_board_id_board_id_fk", "tableFrom": "item", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1664,9 +1479,7 @@ "compositePrimaryKeys": { "item_id": { "name": "item_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1718,12 +1531,8 @@ "name": "layout_board_id_board_id_fk", "tableFrom": "layout", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1731,9 +1540,7 @@ "compositePrimaryKeys": { "layout_id": { "name": "layout_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1799,12 +1606,8 @@ "name": "media_creator_id_user_id_fk", "tableFrom": "media", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1812,9 +1615,7 @@ "compositePrimaryKeys": { "media_id": { "name": "media_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1850,9 +1651,7 @@ "compositePrimaryKeys": { "onboarding_id": { "name": "onboarding_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1925,12 +1724,8 @@ "name": "search_engine_integration_id_integration_id_fk", "tableFrom": "search_engine", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1938,17 +1733,13 @@ "compositePrimaryKeys": { "search_engine_id": { "name": "search_engine_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "search_engine_short_unique": { "name": "search_engine_short_unique", - "columns": [ - "short" - ] + "columns": ["short"] } }, "checkConstraint": {} @@ -1985,12 +1776,8 @@ "name": "section_collapse_state_user_id_user_id_fk", "tableFrom": "section_collapse_state", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1998,12 +1785,8 @@ "name": "section_collapse_state_section_id_section_id_fk", "tableFrom": "section_collapse_state", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2011,10 +1794,7 @@ "compositePrimaryKeys": { "section_collapse_state_user_id_section_id_pk": { "name": "section_collapse_state_user_id_section_id_pk", - "columns": [ - "user_id", - "section_id" - ] + "columns": ["user_id", "section_id"] } }, "uniqueConstraints": {}, @@ -2079,12 +1859,8 @@ "name": "section_layout_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2092,12 +1868,8 @@ "name": "section_layout_layout_id_layout_id_fk", "tableFrom": "section_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2105,12 +1877,8 @@ "name": "section_layout_parent_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "parent_section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2118,10 +1886,7 @@ "compositePrimaryKeys": { "section_layout_section_id_layout_id_pk": { "name": "section_layout_section_id_layout_id_pk", - "columns": [ - "section_id", - "layout_id" - ] + "columns": ["section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -2187,12 +1952,8 @@ "name": "section_board_id_board_id_fk", "tableFrom": "section", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2200,9 +1961,7 @@ "compositePrimaryKeys": { "section_id": { "name": "section_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -2232,17 +1991,13 @@ "compositePrimaryKeys": { "serverSetting_setting_key": { "name": "serverSetting_setting_key", - "columns": [ - "setting_key" - ] + "columns": ["setting_key"] } }, "uniqueConstraints": { "serverSetting_settingKey_unique": { "name": "serverSetting_settingKey_unique", - "columns": [ - "setting_key" - ] + "columns": ["setting_key"] } }, "checkConstraint": {} @@ -2275,9 +2030,7 @@ "indexes": { "user_id_idx": { "name": "user_id_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -2286,12 +2039,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2299,9 +2048,7 @@ "compositePrimaryKeys": { "session_session_token": { "name": "session_session_token", - "columns": [ - "session_token" - ] + "columns": ["session_token"] } }, "uniqueConstraints": {}, @@ -2444,12 +2191,8 @@ "name": "user_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2457,12 +2200,8 @@ "name": "user_mobile_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2470,12 +2209,8 @@ "name": "user_default_search_engine_id_search_engine_id_fk", "tableFrom": "user", "tableTo": "search_engine", - "columnsFrom": [ - "default_search_engine_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2483,9 +2218,7 @@ "compositePrimaryKeys": { "user_id": { "name": "user_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -2521,10 +2254,7 @@ "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { "name": "verificationToken_identifier_token_pk", - "columns": [ - "identifier", - "token" - ] + "columns": ["identifier", "token"] } }, "uniqueConstraints": {}, @@ -2560,10 +2290,7 @@ "compositePrimaryKeys": { "trusted_certificate_hostname_hostname_thumbprint_pk": { "name": "trusted_certificate_hostname_hostname_thumbprint_pk", - "columns": [ - "hostname", - "thumbprint" - ] + "columns": ["hostname", "thumbprint"] } }, "uniqueConstraints": {}, diff --git a/packages/db/migrations/mysql/meta/0042_snapshot.json b/packages/db/migrations/mysql/meta/0042_snapshot.json index d5a1910a9..ba6c70fa5 100644 --- a/packages/db/migrations/mysql/meta/0042_snapshot.json +++ b/packages/db/migrations/mysql/meta/0042_snapshot.json @@ -88,9 +88,7 @@ "indexes": { "userId_idx": { "name": "userId_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -99,12 +97,8 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -112,10 +106,7 @@ "compositePrimaryKeys": { "account_provider_provider_account_id_pk": { "name": "account_provider_provider_account_id_pk", - "columns": [ - "provider", - "provider_account_id" - ] + "columns": ["provider", "provider_account_id"] } }, "uniqueConstraints": {}, @@ -152,12 +143,8 @@ "name": "apiKey_user_id_user_id_fk", "tableFrom": "apiKey", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -165,9 +152,7 @@ "compositePrimaryKeys": { "apiKey_id": { "name": "apiKey_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -224,9 +209,7 @@ "compositePrimaryKeys": { "app_id": { "name": "app_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -263,12 +246,8 @@ "name": "boardGroupPermission_board_id_board_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -276,12 +255,8 @@ "name": "boardGroupPermission_group_id_group_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -289,11 +264,7 @@ "compositePrimaryKeys": { "boardGroupPermission_board_id_group_id_permission_pk": { "name": "boardGroupPermission_board_id_group_id_permission_pk", - "columns": [ - "board_id", - "group_id", - "permission" - ] + "columns": ["board_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -330,12 +301,8 @@ "name": "boardUserPermission_board_id_board_id_fk", "tableFrom": "boardUserPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -343,12 +310,8 @@ "name": "boardUserPermission_user_id_user_id_fk", "tableFrom": "boardUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -356,11 +319,7 @@ "compositePrimaryKeys": { "boardUserPermission_board_id_user_id_permission_pk": { "name": "boardUserPermission_board_id_user_id_permission_pk", - "columns": [ - "board_id", - "user_id", - "permission" - ] + "columns": ["board_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -518,12 +477,8 @@ "name": "board_creator_id_user_id_fk", "tableFrom": "board", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -531,17 +486,13 @@ "compositePrimaryKeys": { "board_id": { "name": "board_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "board_name_unique": { "name": "board_name_unique", - "columns": [ - "name" - ] + "columns": ["name"] } }, "checkConstraint": {} @@ -577,9 +528,7 @@ "compositePrimaryKeys": { "cron_job_configuration_name": { "name": "cron_job_configuration_name", - "columns": [ - "name" - ] + "columns": ["name"] } }, "uniqueConstraints": {}, @@ -707,12 +656,8 @@ "name": "custom_widget_definition_creator_id_user_id_fk", "tableFrom": "custom_widget_definition", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -720,9 +665,7 @@ "compositePrimaryKeys": { "custom_widget_definition_id": { "name": "custom_widget_definition_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -766,12 +709,8 @@ "name": "cw_secret_definition_id_cw_definition_id_fk", "tableFrom": "custom_widget_secret", "tableTo": "custom_widget_definition", - "columnsFrom": [ - "definition_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -779,10 +718,7 @@ "compositePrimaryKeys": { "custom_widget_secret_definition_id_kind_pk": { "name": "custom_widget_secret_definition_id_kind_pk", - "columns": [ - "definition_id", - "kind" - ] + "columns": ["definition_id", "kind"] } }, "uniqueConstraints": {}, @@ -812,12 +748,8 @@ "name": "groupMember_group_id_group_id_fk", "tableFrom": "groupMember", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -825,12 +757,8 @@ "name": "groupMember_user_id_user_id_fk", "tableFrom": "groupMember", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -838,10 +766,7 @@ "compositePrimaryKeys": { "groupMember_group_id_user_id_pk": { "name": "groupMember_group_id_user_id_pk", - "columns": [ - "group_id", - "user_id" - ] + "columns": ["group_id", "user_id"] } }, "uniqueConstraints": {}, @@ -871,12 +796,8 @@ "name": "groupPermission_group_id_group_id_fk", "tableFrom": "groupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -937,12 +858,8 @@ "name": "group_owner_id_user_id_fk", "tableFrom": "group", "tableTo": "user", - "columnsFrom": [ - "owner_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -950,12 +867,8 @@ "name": "group_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -963,12 +876,8 @@ "name": "group_mobile_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -976,17 +885,13 @@ "compositePrimaryKeys": { "group_id": { "name": "group_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "group_name_unique": { "name": "group_name_unique", - "columns": [ - "name" - ] + "columns": ["name"] } }, "checkConstraint": {} @@ -1014,9 +919,7 @@ "compositePrimaryKeys": { "iconRepository_id": { "name": "iconRepository_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1067,12 +970,8 @@ "name": "icon_icon_repository_id_iconRepository_id_fk", "tableFrom": "icon", "tableTo": "iconRepository", - "columnsFrom": [ - "icon_repository_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1080,9 +979,7 @@ "compositePrimaryKeys": { "icon_id": { "name": "icon_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1119,12 +1016,8 @@ "name": "integrationGroupPermissions_integration_id_integration_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1132,12 +1025,8 @@ "name": "integrationGroupPermissions_group_id_group_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1145,11 +1034,7 @@ "compositePrimaryKeys": { "integration_group_permission__pk": { "name": "integration_group_permission__pk", - "columns": [ - "integration_id", - "group_id", - "permission" - ] + "columns": ["integration_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -1179,12 +1064,8 @@ "name": "integration_item_item_id_item_id_fk", "tableFrom": "integration_item", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1192,12 +1073,8 @@ "name": "integration_item_integration_id_integration_id_fk", "tableFrom": "integration_item", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1205,10 +1082,7 @@ "compositePrimaryKeys": { "integration_item_item_id_integration_id_pk": { "name": "integration_item_item_id_integration_id_pk", - "columns": [ - "item_id", - "integration_id" - ] + "columns": ["item_id", "integration_id"] } }, "uniqueConstraints": {}, @@ -1249,16 +1123,12 @@ "indexes": { "integration_secret__kind_idx": { "name": "integration_secret__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false }, "integration_secret__updated_at_idx": { "name": "integration_secret__updated_at_idx", - "columns": [ - "updated_at" - ], + "columns": ["updated_at"], "isUnique": false } }, @@ -1267,12 +1137,8 @@ "name": "integrationSecret_integration_id_integration_id_fk", "tableFrom": "integrationSecret", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1280,10 +1146,7 @@ "compositePrimaryKeys": { "integrationSecret_integration_id_kind_pk": { "name": "integrationSecret_integration_id_kind_pk", - "columns": [ - "integration_id", - "kind" - ] + "columns": ["integration_id", "kind"] } }, "uniqueConstraints": {}, @@ -1320,12 +1183,8 @@ "name": "integrationUserPermission_integration_id_integration_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1333,12 +1192,8 @@ "name": "integrationUserPermission_user_id_user_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1346,11 +1201,7 @@ "compositePrimaryKeys": { "integrationUserPermission_integration_id_user_id_permission_pk": { "name": "integrationUserPermission_integration_id_user_id_permission_pk", - "columns": [ - "integration_id", - "user_id", - "permission" - ] + "columns": ["integration_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -1398,9 +1249,7 @@ "indexes": { "integration__kind_idx": { "name": "integration__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false } }, @@ -1409,12 +1258,8 @@ "name": "integration_app_id_app_id_fk", "tableFrom": "integration", "tableTo": "app", - "columnsFrom": [ - "app_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["app_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1422,9 +1267,7 @@ "compositePrimaryKeys": { "integration_id": { "name": "integration_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1468,12 +1311,8 @@ "name": "invite_creator_id_user_id_fk", "tableFrom": "invite", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1481,17 +1320,13 @@ "compositePrimaryKeys": { "invite_id": { "name": "invite_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "invite_token_unique": { "name": "invite_token_unique", - "columns": [ - "token" - ] + "columns": ["token"] } }, "checkConstraint": {} @@ -1555,12 +1390,8 @@ "name": "item_layout_item_id_item_id_fk", "tableFrom": "item_layout", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1568,12 +1399,8 @@ "name": "item_layout_section_id_section_id_fk", "tableFrom": "item_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1581,12 +1408,8 @@ "name": "item_layout_layout_id_layout_id_fk", "tableFrom": "item_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1594,11 +1417,7 @@ "compositePrimaryKeys": { "item_layout_item_id_section_id_layout_id_pk": { "name": "item_layout_item_id_section_id_layout_id_pk", - "columns": [ - "item_id", - "section_id", - "layout_id" - ] + "columns": ["item_id", "section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -1651,12 +1470,8 @@ "name": "item_board_id_board_id_fk", "tableFrom": "item", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1664,9 +1479,7 @@ "compositePrimaryKeys": { "item_id": { "name": "item_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1718,12 +1531,8 @@ "name": "layout_board_id_board_id_fk", "tableFrom": "layout", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1731,9 +1540,7 @@ "compositePrimaryKeys": { "layout_id": { "name": "layout_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1799,12 +1606,8 @@ "name": "media_creator_id_user_id_fk", "tableFrom": "media", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1812,9 +1615,7 @@ "compositePrimaryKeys": { "media_id": { "name": "media_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1850,9 +1651,7 @@ "compositePrimaryKeys": { "onboarding_id": { "name": "onboarding_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -1925,12 +1724,8 @@ "name": "search_engine_integration_id_integration_id_fk", "tableFrom": "search_engine", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1938,17 +1733,13 @@ "compositePrimaryKeys": { "search_engine_id": { "name": "search_engine_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": { "search_engine_short_unique": { "name": "search_engine_short_unique", - "columns": [ - "short" - ] + "columns": ["short"] } }, "checkConstraint": {} @@ -1985,12 +1776,8 @@ "name": "section_collapse_state_user_id_user_id_fk", "tableFrom": "section_collapse_state", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1998,12 +1785,8 @@ "name": "section_collapse_state_section_id_section_id_fk", "tableFrom": "section_collapse_state", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2011,10 +1794,7 @@ "compositePrimaryKeys": { "section_collapse_state_user_id_section_id_pk": { "name": "section_collapse_state_user_id_section_id_pk", - "columns": [ - "user_id", - "section_id" - ] + "columns": ["user_id", "section_id"] } }, "uniqueConstraints": {}, @@ -2079,12 +1859,8 @@ "name": "section_layout_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2092,12 +1868,8 @@ "name": "section_layout_layout_id_layout_id_fk", "tableFrom": "section_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2105,12 +1877,8 @@ "name": "section_layout_parent_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "parent_section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2118,10 +1886,7 @@ "compositePrimaryKeys": { "section_layout_section_id_layout_id_pk": { "name": "section_layout_section_id_layout_id_pk", - "columns": [ - "section_id", - "layout_id" - ] + "columns": ["section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -2187,12 +1952,8 @@ "name": "section_board_id_board_id_fk", "tableFrom": "section", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2200,9 +1961,7 @@ "compositePrimaryKeys": { "section_id": { "name": "section_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -2232,17 +1991,13 @@ "compositePrimaryKeys": { "serverSetting_setting_key": { "name": "serverSetting_setting_key", - "columns": [ - "setting_key" - ] + "columns": ["setting_key"] } }, "uniqueConstraints": { "serverSetting_settingKey_unique": { "name": "serverSetting_settingKey_unique", - "columns": [ - "setting_key" - ] + "columns": ["setting_key"] } }, "checkConstraint": {} @@ -2275,9 +2030,7 @@ "indexes": { "user_id_idx": { "name": "user_id_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -2286,12 +2039,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2299,9 +2048,7 @@ "compositePrimaryKeys": { "session_session_token": { "name": "session_session_token", - "columns": [ - "session_token" - ] + "columns": ["session_token"] } }, "uniqueConstraints": {}, @@ -2444,12 +2191,8 @@ "name": "user_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2457,12 +2200,8 @@ "name": "user_mobile_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2470,12 +2209,8 @@ "name": "user_default_search_engine_id_search_engine_id_fk", "tableFrom": "user", "tableTo": "search_engine", - "columnsFrom": [ - "default_search_engine_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2483,9 +2218,7 @@ "compositePrimaryKeys": { "user_id": { "name": "user_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -2521,10 +2254,7 @@ "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { "name": "verificationToken_identifier_token_pk", - "columns": [ - "identifier", - "token" - ] + "columns": ["identifier", "token"] } }, "uniqueConstraints": {}, @@ -2560,10 +2290,7 @@ "compositePrimaryKeys": { "trusted_certificate_hostname_hostname_thumbprint_pk": { "name": "trusted_certificate_hostname_hostname_thumbprint_pk", - "columns": [ - "hostname", - "thumbprint" - ] + "columns": ["hostname", "thumbprint"] } }, "uniqueConstraints": {}, @@ -2607,22 +2334,15 @@ "name": "widget_secret_item_id_item_id_fk", "tableFrom": "widget_secret", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "widget_secret_item_id_kind_pk": { - "columns": [ - "item_id", - "kind" - ], + "columns": ["item_id", "kind"], "name": "widget_secret_item_id_kind_pk" } }, diff --git a/packages/db/migrations/mysql/meta/0047_snapshot.json b/packages/db/migrations/mysql/meta/0047_snapshot.json new file mode 100644 index 000000000..2b9d5d3f5 --- /dev/null +++ b/packages/db/migrations/mysql/meta/0047_snapshot.json @@ -0,0 +1,2809 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "5d4a439e-2e7b-4845-a6b4-f24ca5b95408", + "prevId": "d1b4dec4-07ef-498d-9fe0-0c61e93c0664", + "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 + }, + "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 + }, + "ping_url": { + "name": "ping_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "app_id": { + "name": "app_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "assistant_configuration": { + "name": "assistant_configuration", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'default'" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "web_search_enabled": { + "name": "web_search_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "provider": { + "name": "provider", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'openrouter'" + }, + "base_url": { + "name": "base_url", + "type": "varchar(2048)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'https://openrouter.ai/api/v1'" + }, + "model_discovery_path": { + "name": "model_discovery_path", + "type": "varchar(512)", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'/models'" + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "encrypted_headers": { + "name": "encrypted_headers", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "assistant_configuration_id": { + "name": "assistant_configuration_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "assistant_message": { + "name": "assistant_message", + "columns": { + "id": { + "name": "id", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "parent_id": { + "name": "parent_id", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "format": { + "name": "format", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'ai-sdk/v6'" + }, + "content": { + "name": "content", + "type": "mediumtext", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": { + "assistant_message__thread_id_created_at_idx": { + "name": "assistant_message__thread_id_created_at_idx", + "columns": ["thread_id", "created_at"], + "isUnique": false + } + }, + "foreignKeys": { + "assistant_message_thread_id_assistant_thread_id_fk": { + "name": "assistant_message_thread_id_assistant_thread_id_fk", + "tableFrom": "assistant_message", + "tableTo": "assistant_thread", + "columnsFrom": ["thread_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "assistant_message_id": { + "name": "assistant_message_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "assistant_thread": { + "name": "assistant_thread", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + } + }, + "indexes": { + "assistant_thread__user_id_updated_at_idx": { + "name": "assistant_thread__user_id_updated_at_idx", + "columns": ["user_id", "updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "assistant_thread_user_id_user_id_fk": { + "name": "assistant_thread_user_id_user_id_fk", + "tableFrom": "assistant_thread", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "assistant_thread_id": { + "name": "assistant_thread_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 + }, + "icon_color": { + "name": "icon_color", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "item_radius": { + "name": "item_radius", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('lg')" + }, + "disable_status": { + "name": "disable_status", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "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": {} + }, + "cron_job_configuration": { + "name": "cron_job_configuration", + "columns": { + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cron_expression": { + "name": "cron_expression", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "cron_job_configuration_name": { + "name": "cron_job_configuration_name", + "columns": ["name"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "custom_widget_v2_definition": { + "name": "custom_widget_v2_definition", + "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 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sources": { + "name": "sources", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "requests": { + "name": "requests", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "template": { + "name": "template", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_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": { + "custom_widget_v2_definition_creator_id_user_id_fk": { + "name": "custom_widget_v2_definition_creator_id_user_id_fk", + "tableFrom": "custom_widget_v2_definition", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "custom_widget_v2_definition_id": { + "name": "custom_widget_v2_definition_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "custom_widget_v2_secret": { + "name": "custom_widget_v2_secret", + "columns": { + "source_id": { + "name": "source_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "encrypted_value": { + "name": "encrypted_value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "definition_id": { + "name": "definition_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "custom_widget_v2_secret_definition_id_fk": { + "name": "custom_widget_v2_secret_definition_id_fk", + "tableFrom": "custom_widget_v2_secret", + "tableTo": "custom_widget_v2_definition", + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "custom_widget_v2_secret_definition_id_source_id_kind_pk": { + "name": "custom_widget_v2_secret_definition_id_source_id_kind_pk", + "columns": ["definition_id", "source_id", "kind"] + } + }, + "uniqueConstraints": {}, + "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 + }, + "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 + }, + "position": { + "name": "position", + "type": "smallint", + "primaryKey": false, + "notNull": true, + "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" + }, + "group_home_board_id_board_id_fk": { + "name": "group_home_board_id_board_id_fk", + "tableFrom": "group", + "tableTo": "board", + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "group_mobile_home_board_id_board_id_fk": { + "name": "group_mobile_home_board_id_board_id_fk", + "tableFrom": "group", + "tableTo": "board", + "columnsFrom": ["mobile_home_board_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(64)", + "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 + }, + "app_id": { + "name": "app_id", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": { + "integration_app_id_app_id_fk": { + "name": "integration_app_id_app_id_fk", + "tableFrom": "integration", + "tableTo": "app", + "columnsFrom": ["app_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "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_layout": { + "name": "item_layout", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "layout_id": { + "name": "layout_id", + "type": "varchar(64)", + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "item_layout_item_id_item_id_fk": { + "name": "item_layout_item_id_item_id_fk", + "tableFrom": "item_layout", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "item_layout_section_id_section_id_fk": { + "name": "item_layout_section_id_section_id_fk", + "tableFrom": "item_layout", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "item_layout_layout_id_layout_id_fk": { + "name": "item_layout_layout_id_layout_id_fk", + "tableFrom": "item_layout", + "tableTo": "layout", + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_layout_item_id_section_id_layout_id_pk": { + "name": "item_layout_item_id_section_id_layout_id_pk", + "columns": ["item_id", "section_id", "layout_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "item": { + "name": "item", + "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 + }, + "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_board_id_board_id_fk": { + "name": "item_board_id_board_id_fk", + "tableFrom": "item", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_id": { + "name": "item_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "layout": { + "name": "layout", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "tinyint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "left_gutter_column_count": { + "name": "left_gutter_column_count", + "type": "tinyint", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "right_gutter_column_count": { + "name": "right_gutter_column_count", + "type": "tinyint", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "breakpoint": { + "name": "breakpoint", + "type": "smallint", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "role": { + "name": "role", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'custom'" + } + }, + "indexes": {}, + "foreignKeys": { + "layout_board_id_board_id_fk": { + "name": "layout_board_id_board_id_fk", + "tableFrom": "layout", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "layout_id": { + "name": "layout_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "custom_widget_definition": { + "name": "custom_widget_definition", + "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 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "auth_type": { + "name": "auth_type", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'none'" + }, + "header_name": { + "name": "header_name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "method": { + "name": "method", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'GET'" + }, + "request_body": { + "name": "request_body", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_type": { + "name": "display_type", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'singleValue'" + }, + "display_config": { + "name": "display_config", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "('{\"json\": {}}')" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(now())" + }, + "updated_at": { + "name": "updated_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": { + "custom_widget_definition_creator_id_user_id_fk": { + "name": "custom_widget_definition_creator_id_user_id_fk", + "tableFrom": "custom_widget_definition", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "custom_widget_definition_id": { + "name": "custom_widget_definition_id", + "columns": ["id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "custom_widget_secret": { + "name": "custom_widget_secret", + "columns": { + "kind": { + "name": "kind", + "type": "varchar(64)", + "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 + }, + "definition_id": { + "name": "definition_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "cw_secret_definition_id_cw_definition_id_fk": { + "name": "cw_secret_definition_id_cw_definition_id_fk", + "tableFrom": "custom_widget_secret", + "tableTo": "custom_widget_definition", + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "custom_widget_secret_definition_id_kind_pk": { + "name": "custom_widget_secret_definition_id_kind_pk", + "columns": ["definition_id", "kind"] + } + }, + "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": "LONGBLOB", + "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_collapse_state": { + "name": "section_collapse_state", + "columns": { + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "collapsed": { + "name": "collapsed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_collapse_state_user_id_user_id_fk": { + "name": "section_collapse_state_user_id_user_id_fk", + "tableFrom": "section_collapse_state", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_collapse_state_section_id_section_id_fk": { + "name": "section_collapse_state_section_id_section_id_fk", + "tableFrom": "section_collapse_state", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_collapse_state_user_id_section_id_pk": { + "name": "section_collapse_state_user_id_section_id_pk", + "columns": ["user_id", "section_id"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "section_layout": { + "name": "section_layout", + "columns": { + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "layout_id": { + "name": "layout_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false, + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "section_layout_section_id_section_id_fk": { + "name": "section_layout_section_id_section_id_fk", + "tableFrom": "section_layout", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_layout_layout_id_layout_id_fk": { + "name": "section_layout_layout_id_layout_id_fk", + "tableFrom": "section_layout", + "tableTo": "layout", + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_layout_parent_section_id_section_id_fk": { + "name": "section_layout_parent_section_id_section_id_fk", + "tableFrom": "section_layout", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_layout_section_id_layout_id_pk": { + "name": "section_layout_section_id_layout_id_pk", + "columns": ["section_id", "layout_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": false, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "int", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "('{\"json\": {}}')" + } + }, + "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" + } + }, + "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": {} + }, + "trusted_certificate_hostname": { + "name": "trusted_certificate_hostname", + "columns": { + "hostname": { + "name": "hostname", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "thumbprint": { + "name": "thumbprint", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "certificate": { + "name": "certificate", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "trusted_certificate_hostname_hostname_thumbprint_pk": { + "name": "trusted_certificate_hostname_hostname_thumbprint_pk", + "columns": ["hostname", "thumbprint"] + } + }, + "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 + }, + "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 + }, + "open_search_in_new_tab": { + "name": "open_search_in_new_tab", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "ddg_bangs": { + "name": "ddg_bangs", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "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 + }, + "enable_right_click_on_widgets": { + "name": "enable_right_click_on_widgets", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "completed_manage_tour": { + "name": "completed_manage_tour", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "completed_board_tour": { + "name": "completed_board_tour", + "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": {} + }, + "widget_secret": { + "name": "widget_secret", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "varchar(64)", + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "widget_secret_item_id_item_id_fk": { + "name": "widget_secret_item_id_item_id_fk", + "tableFrom": "widget_secret", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "widget_secret_item_id_kind_pk": { + "name": "widget_secret_item_id_kind_pk", + "columns": ["item_id", "kind"] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} diff --git a/packages/db/migrations/postgresql/0011_same_sir_ram.sql b/packages/db/migrations/postgresql/0011_same_sir_ram.sql deleted file mode 100644 index aa5f5a56e..000000000 --- a/packages/db/migrations/postgresql/0011_same_sir_ram.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "assistant_configuration" ADD COLUMN "web_search_enabled" boolean DEFAULT false NOT NULL; \ No newline at end of file diff --git a/packages/db/migrations/postgresql/meta/0006_snapshot.json b/packages/db/migrations/postgresql/meta/0006_snapshot.json index ee39b4f11..d5576746b 100644 --- a/packages/db/migrations/postgresql/meta/0006_snapshot.json +++ b/packages/db/migrations/postgresql/meta/0006_snapshot.json @@ -97,12 +97,8 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -110,10 +106,7 @@ "compositePrimaryKeys": { "account_provider_provider_account_id_pk": { "name": "account_provider_provider_account_id_pk", - "columns": [ - "provider", - "provider_account_id" - ] + "columns": ["provider", "provider_account_id"] } }, "uniqueConstraints": {}, @@ -150,12 +143,8 @@ "name": "apiKey_user_id_user_id_fk", "tableFrom": "apiKey", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -244,12 +233,8 @@ "name": "boardGroupPermission_board_id_board_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -257,12 +242,8 @@ "name": "boardGroupPermission_group_id_group_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -270,11 +251,7 @@ "compositePrimaryKeys": { "boardGroupPermission_board_id_group_id_permission_pk": { "name": "boardGroupPermission_board_id_group_id_permission_pk", - "columns": [ - "board_id", - "group_id", - "permission" - ] + "columns": ["board_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -311,12 +288,8 @@ "name": "boardUserPermission_board_id_board_id_fk", "tableFrom": "boardUserPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -324,12 +297,8 @@ "name": "boardUserPermission_user_id_user_id_fk", "tableFrom": "boardUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -337,11 +306,7 @@ "compositePrimaryKeys": { "boardUserPermission_board_id_user_id_permission_pk": { "name": "boardUserPermission_board_id_user_id_permission_pk", - "columns": [ - "board_id", - "user_id", - "permission" - ] + "columns": ["board_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -483,12 +448,8 @@ "name": "board_creator_id_user_id_fk", "tableFrom": "board", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -498,9 +459,7 @@ "board_name_unique": { "name": "board_name_unique", "nullsNotDistinct": false, - "columns": [ - "name" - ] + "columns": ["name"] } }, "policies": {}, @@ -646,12 +605,8 @@ "name": "custom_widget_definition_creator_id_user_id_fk", "tableFrom": "custom_widget_definition", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -697,12 +652,8 @@ "name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk", "tableFrom": "custom_widget_secret", "tableTo": "custom_widget_definition", - "columnsFrom": [ - "definition_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -710,10 +661,7 @@ "compositePrimaryKeys": { "custom_widget_secret_definition_id_kind_pk": { "name": "custom_widget_secret_definition_id_kind_pk", - "columns": [ - "definition_id", - "kind" - ] + "columns": ["definition_id", "kind"] } }, "uniqueConstraints": {}, @@ -744,12 +692,8 @@ "name": "groupMember_group_id_group_id_fk", "tableFrom": "groupMember", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -757,12 +701,8 @@ "name": "groupMember_user_id_user_id_fk", "tableFrom": "groupMember", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -770,10 +710,7 @@ "compositePrimaryKeys": { "groupMember_group_id_user_id_pk": { "name": "groupMember_group_id_user_id_pk", - "columns": [ - "group_id", - "user_id" - ] + "columns": ["group_id", "user_id"] } }, "uniqueConstraints": {}, @@ -804,12 +741,8 @@ "name": "groupPermission_group_id_group_id_fk", "tableFrom": "groupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -867,12 +800,8 @@ "name": "group_owner_id_user_id_fk", "tableFrom": "group", "tableTo": "user", - "columnsFrom": [ - "owner_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -880,12 +809,8 @@ "name": "group_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -893,12 +818,8 @@ "name": "group_mobile_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -908,9 +829,7 @@ "group_name_unique": { "name": "group_name_unique", "nullsNotDistinct": false, - "columns": [ - "name" - ] + "columns": ["name"] } }, "policies": {}, @@ -983,12 +902,8 @@ "name": "icon_icon_repository_id_iconRepository_id_fk", "tableFrom": "icon", "tableTo": "iconRepository", - "columnsFrom": [ - "icon_repository_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1028,12 +943,8 @@ "name": "integrationGroupPermissions_integration_id_integration_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1041,12 +952,8 @@ "name": "integrationGroupPermissions_group_id_group_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1054,11 +961,7 @@ "compositePrimaryKeys": { "integration_group_permission__pk": { "name": "integration_group_permission__pk", - "columns": [ - "integration_id", - "group_id", - "permission" - ] + "columns": ["integration_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -1089,12 +992,8 @@ "name": "integration_item_item_id_item_id_fk", "tableFrom": "integration_item", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1102,12 +1001,8 @@ "name": "integration_item_integration_id_integration_id_fk", "tableFrom": "integration_item", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1115,10 +1010,7 @@ "compositePrimaryKeys": { "integration_item_item_id_integration_id_pk": { "name": "integration_item_item_id_integration_id_pk", - "columns": [ - "item_id", - "integration_id" - ] + "columns": ["item_id", "integration_id"] } }, "uniqueConstraints": {}, @@ -1192,12 +1084,8 @@ "name": "integrationSecret_integration_id_integration_id_fk", "tableFrom": "integrationSecret", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1205,10 +1093,7 @@ "compositePrimaryKeys": { "integrationSecret_integration_id_kind_pk": { "name": "integrationSecret_integration_id_kind_pk", - "columns": [ - "integration_id", - "kind" - ] + "columns": ["integration_id", "kind"] } }, "uniqueConstraints": {}, @@ -1245,12 +1130,8 @@ "name": "integrationUserPermission_integration_id_integration_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1258,12 +1139,8 @@ "name": "integrationUserPermission_user_id_user_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1271,11 +1148,7 @@ "compositePrimaryKeys": { "integrationUserPermission_integration_id_user_id_permission_pk": { "name": "integrationUserPermission_integration_id_user_id_permission_pk", - "columns": [ - "integration_id", - "user_id", - "permission" - ] + "columns": ["integration_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -1340,12 +1213,8 @@ "name": "integration_app_id_app_id_fk", "tableFrom": "integration", "tableTo": "app", - "columnsFrom": [ - "app_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["app_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1391,12 +1260,8 @@ "name": "invite_creator_id_user_id_fk", "tableFrom": "invite", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1406,9 +1271,7 @@ "invite_token_unique": { "name": "invite_token_unique", "nullsNotDistinct": false, - "columns": [ - "token" - ] + "columns": ["token"] } }, "policies": {}, @@ -1468,12 +1331,8 @@ "name": "item_layout_item_id_item_id_fk", "tableFrom": "item_layout", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1481,12 +1340,8 @@ "name": "item_layout_section_id_section_id_fk", "tableFrom": "item_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1494,12 +1349,8 @@ "name": "item_layout_layout_id_layout_id_fk", "tableFrom": "item_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1507,11 +1358,7 @@ "compositePrimaryKeys": { "item_layout_item_id_section_id_layout_id_pk": { "name": "item_layout_item_id_section_id_layout_id_pk", - "columns": [ - "item_id", - "section_id", - "layout_id" - ] + "columns": ["item_id", "section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -1562,12 +1409,8 @@ "name": "item_board_id_board_id_fk", "tableFrom": "item", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1620,12 +1463,8 @@ "name": "layout_board_id_board_id_fk", "tableFrom": "layout", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1690,12 +1529,8 @@ "name": "media_creator_id_user_id_fk", "tableFrom": "media", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1797,12 +1632,8 @@ "name": "search_engine_integration_id_integration_id_fk", "tableFrom": "search_engine", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1812,9 +1643,7 @@ "search_engine_short_unique": { "name": "search_engine_short_unique", "nullsNotDistinct": false, - "columns": [ - "short" - ] + "columns": ["short"] } }, "policies": {}, @@ -1851,12 +1680,8 @@ "name": "section_collapse_state_user_id_user_id_fk", "tableFrom": "section_collapse_state", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1864,12 +1689,8 @@ "name": "section_collapse_state_section_id_section_id_fk", "tableFrom": "section_collapse_state", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1877,10 +1698,7 @@ "compositePrimaryKeys": { "section_collapse_state_user_id_section_id_pk": { "name": "section_collapse_state_user_id_section_id_pk", - "columns": [ - "user_id", - "section_id" - ] + "columns": ["user_id", "section_id"] } }, "uniqueConstraints": {}, @@ -1941,12 +1759,8 @@ "name": "section_layout_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1954,12 +1768,8 @@ "name": "section_layout_layout_id_layout_id_fk", "tableFrom": "section_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1967,12 +1777,8 @@ "name": "section_layout_parent_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "parent_section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1980,10 +1786,7 @@ "compositePrimaryKeys": { "section_layout_section_id_layout_id_pk": { "name": "section_layout_section_id_layout_id_pk", - "columns": [ - "section_id", - "layout_id" - ] + "columns": ["section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -2045,12 +1848,8 @@ "name": "section_board_id_board_id_fk", "tableFrom": "section", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2086,9 +1885,7 @@ "serverSetting_settingKey_unique": { "name": "serverSetting_settingKey_unique", "nullsNotDistinct": false, - "columns": [ - "setting_key" - ] + "columns": ["setting_key"] } }, "policies": {}, @@ -2140,12 +1937,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2277,12 +2070,8 @@ "name": "user_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2290,12 +2079,8 @@ "name": "user_mobile_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2303,12 +2088,8 @@ "name": "user_default_search_engine_id_search_engine_id_fk", "tableFrom": "user", "tableTo": "search_engine", - "columnsFrom": [ - "default_search_engine_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2347,10 +2128,7 @@ "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { "name": "verificationToken_identifier_token_pk", - "columns": [ - "identifier", - "token" - ] + "columns": ["identifier", "token"] } }, "uniqueConstraints": {}, @@ -2386,10 +2164,7 @@ "compositePrimaryKeys": { "trusted_certificate_hostname_hostname_thumbprint_pk": { "name": "trusted_certificate_hostname_hostname_thumbprint_pk", - "columns": [ - "hostname", - "thumbprint" - ] + "columns": ["hostname", "thumbprint"] } }, "uniqueConstraints": {}, @@ -2409,4 +2184,4 @@ "schemas": {}, "tables": {} } -} \ No newline at end of file +} diff --git a/packages/db/migrations/postgresql/meta/0007_snapshot.json b/packages/db/migrations/postgresql/meta/0007_snapshot.json index 4c4f167d7..de8042930 100644 --- a/packages/db/migrations/postgresql/meta/0007_snapshot.json +++ b/packages/db/migrations/postgresql/meta/0007_snapshot.json @@ -97,12 +97,8 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -110,10 +106,7 @@ "compositePrimaryKeys": { "account_provider_provider_account_id_pk": { "name": "account_provider_provider_account_id_pk", - "columns": [ - "provider", - "provider_account_id" - ] + "columns": ["provider", "provider_account_id"] } }, "uniqueConstraints": {}, @@ -150,12 +143,8 @@ "name": "apiKey_user_id_user_id_fk", "tableFrom": "apiKey", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -244,12 +233,8 @@ "name": "boardGroupPermission_board_id_board_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -257,12 +242,8 @@ "name": "boardGroupPermission_group_id_group_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -270,11 +251,7 @@ "compositePrimaryKeys": { "boardGroupPermission_board_id_group_id_permission_pk": { "name": "boardGroupPermission_board_id_group_id_permission_pk", - "columns": [ - "board_id", - "group_id", - "permission" - ] + "columns": ["board_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -311,12 +288,8 @@ "name": "boardUserPermission_board_id_board_id_fk", "tableFrom": "boardUserPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -324,12 +297,8 @@ "name": "boardUserPermission_user_id_user_id_fk", "tableFrom": "boardUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -337,11 +306,7 @@ "compositePrimaryKeys": { "boardUserPermission_board_id_user_id_permission_pk": { "name": "boardUserPermission_board_id_user_id_permission_pk", - "columns": [ - "board_id", - "user_id", - "permission" - ] + "columns": ["board_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -483,12 +448,8 @@ "name": "board_creator_id_user_id_fk", "tableFrom": "board", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -498,9 +459,7 @@ "board_name_unique": { "name": "board_name_unique", "nullsNotDistinct": false, - "columns": [ - "name" - ] + "columns": ["name"] } }, "policies": {}, @@ -647,12 +606,8 @@ "name": "custom_widget_definition_creator_id_user_id_fk", "tableFrom": "custom_widget_definition", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -698,12 +653,8 @@ "name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk", "tableFrom": "custom_widget_secret", "tableTo": "custom_widget_definition", - "columnsFrom": [ - "definition_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -711,10 +662,7 @@ "compositePrimaryKeys": { "custom_widget_secret_definition_id_kind_pk": { "name": "custom_widget_secret_definition_id_kind_pk", - "columns": [ - "definition_id", - "kind" - ] + "columns": ["definition_id", "kind"] } }, "uniqueConstraints": {}, @@ -745,12 +693,8 @@ "name": "groupMember_group_id_group_id_fk", "tableFrom": "groupMember", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -758,12 +702,8 @@ "name": "groupMember_user_id_user_id_fk", "tableFrom": "groupMember", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -771,10 +711,7 @@ "compositePrimaryKeys": { "groupMember_group_id_user_id_pk": { "name": "groupMember_group_id_user_id_pk", - "columns": [ - "group_id", - "user_id" - ] + "columns": ["group_id", "user_id"] } }, "uniqueConstraints": {}, @@ -805,12 +742,8 @@ "name": "groupPermission_group_id_group_id_fk", "tableFrom": "groupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -868,12 +801,8 @@ "name": "group_owner_id_user_id_fk", "tableFrom": "group", "tableTo": "user", - "columnsFrom": [ - "owner_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -881,12 +810,8 @@ "name": "group_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -894,12 +819,8 @@ "name": "group_mobile_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -909,9 +830,7 @@ "group_name_unique": { "name": "group_name_unique", "nullsNotDistinct": false, - "columns": [ - "name" - ] + "columns": ["name"] } }, "policies": {}, @@ -984,12 +903,8 @@ "name": "icon_icon_repository_id_iconRepository_id_fk", "tableFrom": "icon", "tableTo": "iconRepository", - "columnsFrom": [ - "icon_repository_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1029,12 +944,8 @@ "name": "integrationGroupPermissions_integration_id_integration_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1042,12 +953,8 @@ "name": "integrationGroupPermissions_group_id_group_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1055,11 +962,7 @@ "compositePrimaryKeys": { "integration_group_permission__pk": { "name": "integration_group_permission__pk", - "columns": [ - "integration_id", - "group_id", - "permission" - ] + "columns": ["integration_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -1090,12 +993,8 @@ "name": "integration_item_item_id_item_id_fk", "tableFrom": "integration_item", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1103,12 +1002,8 @@ "name": "integration_item_integration_id_integration_id_fk", "tableFrom": "integration_item", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1116,10 +1011,7 @@ "compositePrimaryKeys": { "integration_item_item_id_integration_id_pk": { "name": "integration_item_item_id_integration_id_pk", - "columns": [ - "item_id", - "integration_id" - ] + "columns": ["item_id", "integration_id"] } }, "uniqueConstraints": {}, @@ -1193,12 +1085,8 @@ "name": "integrationSecret_integration_id_integration_id_fk", "tableFrom": "integrationSecret", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1206,10 +1094,7 @@ "compositePrimaryKeys": { "integrationSecret_integration_id_kind_pk": { "name": "integrationSecret_integration_id_kind_pk", - "columns": [ - "integration_id", - "kind" - ] + "columns": ["integration_id", "kind"] } }, "uniqueConstraints": {}, @@ -1246,12 +1131,8 @@ "name": "integrationUserPermission_integration_id_integration_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1259,12 +1140,8 @@ "name": "integrationUserPermission_user_id_user_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1272,11 +1149,7 @@ "compositePrimaryKeys": { "integrationUserPermission_integration_id_user_id_permission_pk": { "name": "integrationUserPermission_integration_id_user_id_permission_pk", - "columns": [ - "integration_id", - "user_id", - "permission" - ] + "columns": ["integration_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -1341,12 +1214,8 @@ "name": "integration_app_id_app_id_fk", "tableFrom": "integration", "tableTo": "app", - "columnsFrom": [ - "app_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["app_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1392,12 +1261,8 @@ "name": "invite_creator_id_user_id_fk", "tableFrom": "invite", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1407,9 +1272,7 @@ "invite_token_unique": { "name": "invite_token_unique", "nullsNotDistinct": false, - "columns": [ - "token" - ] + "columns": ["token"] } }, "policies": {}, @@ -1469,12 +1332,8 @@ "name": "item_layout_item_id_item_id_fk", "tableFrom": "item_layout", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1482,12 +1341,8 @@ "name": "item_layout_section_id_section_id_fk", "tableFrom": "item_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1495,12 +1350,8 @@ "name": "item_layout_layout_id_layout_id_fk", "tableFrom": "item_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1508,11 +1359,7 @@ "compositePrimaryKeys": { "item_layout_item_id_section_id_layout_id_pk": { "name": "item_layout_item_id_section_id_layout_id_pk", - "columns": [ - "item_id", - "section_id", - "layout_id" - ] + "columns": ["item_id", "section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -1563,12 +1410,8 @@ "name": "item_board_id_board_id_fk", "tableFrom": "item", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1621,12 +1464,8 @@ "name": "layout_board_id_board_id_fk", "tableFrom": "layout", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1691,12 +1530,8 @@ "name": "media_creator_id_user_id_fk", "tableFrom": "media", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1798,12 +1633,8 @@ "name": "search_engine_integration_id_integration_id_fk", "tableFrom": "search_engine", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1813,9 +1644,7 @@ "search_engine_short_unique": { "name": "search_engine_short_unique", "nullsNotDistinct": false, - "columns": [ - "short" - ] + "columns": ["short"] } }, "policies": {}, @@ -1852,12 +1681,8 @@ "name": "section_collapse_state_user_id_user_id_fk", "tableFrom": "section_collapse_state", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1865,12 +1690,8 @@ "name": "section_collapse_state_section_id_section_id_fk", "tableFrom": "section_collapse_state", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1878,10 +1699,7 @@ "compositePrimaryKeys": { "section_collapse_state_user_id_section_id_pk": { "name": "section_collapse_state_user_id_section_id_pk", - "columns": [ - "user_id", - "section_id" - ] + "columns": ["user_id", "section_id"] } }, "uniqueConstraints": {}, @@ -1942,12 +1760,8 @@ "name": "section_layout_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1955,12 +1769,8 @@ "name": "section_layout_layout_id_layout_id_fk", "tableFrom": "section_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1968,12 +1778,8 @@ "name": "section_layout_parent_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "parent_section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1981,10 +1787,7 @@ "compositePrimaryKeys": { "section_layout_section_id_layout_id_pk": { "name": "section_layout_section_id_layout_id_pk", - "columns": [ - "section_id", - "layout_id" - ] + "columns": ["section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -2046,12 +1849,8 @@ "name": "section_board_id_board_id_fk", "tableFrom": "section", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2087,9 +1886,7 @@ "serverSetting_settingKey_unique": { "name": "serverSetting_settingKey_unique", "nullsNotDistinct": false, - "columns": [ - "setting_key" - ] + "columns": ["setting_key"] } }, "policies": {}, @@ -2141,12 +1938,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2278,12 +2071,8 @@ "name": "user_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2291,12 +2080,8 @@ "name": "user_mobile_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2304,12 +2089,8 @@ "name": "user_default_search_engine_id_search_engine_id_fk", "tableFrom": "user", "tableTo": "search_engine", - "columnsFrom": [ - "default_search_engine_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2348,10 +2129,7 @@ "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { "name": "verificationToken_identifier_token_pk", - "columns": [ - "identifier", - "token" - ] + "columns": ["identifier", "token"] } }, "uniqueConstraints": {}, @@ -2387,10 +2165,7 @@ "compositePrimaryKeys": { "trusted_certificate_hostname_hostname_thumbprint_pk": { "name": "trusted_certificate_hostname_hostname_thumbprint_pk", - "columns": [ - "hostname", - "thumbprint" - ] + "columns": ["hostname", "thumbprint"] } }, "uniqueConstraints": {}, diff --git a/packages/db/migrations/postgresql/meta/0008_snapshot.json b/packages/db/migrations/postgresql/meta/0008_snapshot.json index ab3303ac9..4ab88d535 100644 --- a/packages/db/migrations/postgresql/meta/0008_snapshot.json +++ b/packages/db/migrations/postgresql/meta/0008_snapshot.json @@ -97,12 +97,8 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -110,10 +106,7 @@ "compositePrimaryKeys": { "account_provider_provider_account_id_pk": { "name": "account_provider_provider_account_id_pk", - "columns": [ - "provider", - "provider_account_id" - ] + "columns": ["provider", "provider_account_id"] } }, "uniqueConstraints": {}, @@ -150,12 +143,8 @@ "name": "apiKey_user_id_user_id_fk", "tableFrom": "apiKey", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -244,12 +233,8 @@ "name": "boardGroupPermission_board_id_board_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -257,12 +242,8 @@ "name": "boardGroupPermission_group_id_group_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -270,11 +251,7 @@ "compositePrimaryKeys": { "boardGroupPermission_board_id_group_id_permission_pk": { "name": "boardGroupPermission_board_id_group_id_permission_pk", - "columns": [ - "board_id", - "group_id", - "permission" - ] + "columns": ["board_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -311,12 +288,8 @@ "name": "boardUserPermission_board_id_board_id_fk", "tableFrom": "boardUserPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -324,12 +297,8 @@ "name": "boardUserPermission_user_id_user_id_fk", "tableFrom": "boardUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -337,11 +306,7 @@ "compositePrimaryKeys": { "boardUserPermission_board_id_user_id_permission_pk": { "name": "boardUserPermission_board_id_user_id_permission_pk", - "columns": [ - "board_id", - "user_id", - "permission" - ] + "columns": ["board_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -483,12 +448,8 @@ "name": "board_creator_id_user_id_fk", "tableFrom": "board", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -498,9 +459,7 @@ "board_name_unique": { "name": "board_name_unique", "nullsNotDistinct": false, - "columns": [ - "name" - ] + "columns": ["name"] } }, "policies": {}, @@ -647,12 +606,8 @@ "name": "custom_widget_definition_creator_id_user_id_fk", "tableFrom": "custom_widget_definition", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -698,12 +653,8 @@ "name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk", "tableFrom": "custom_widget_secret", "tableTo": "custom_widget_definition", - "columnsFrom": [ - "definition_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -711,10 +662,7 @@ "compositePrimaryKeys": { "custom_widget_secret_definition_id_kind_pk": { "name": "custom_widget_secret_definition_id_kind_pk", - "columns": [ - "definition_id", - "kind" - ] + "columns": ["definition_id", "kind"] } }, "uniqueConstraints": {}, @@ -745,12 +693,8 @@ "name": "groupMember_group_id_group_id_fk", "tableFrom": "groupMember", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -758,12 +702,8 @@ "name": "groupMember_user_id_user_id_fk", "tableFrom": "groupMember", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -771,10 +711,7 @@ "compositePrimaryKeys": { "groupMember_group_id_user_id_pk": { "name": "groupMember_group_id_user_id_pk", - "columns": [ - "group_id", - "user_id" - ] + "columns": ["group_id", "user_id"] } }, "uniqueConstraints": {}, @@ -805,12 +742,8 @@ "name": "groupPermission_group_id_group_id_fk", "tableFrom": "groupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -868,12 +801,8 @@ "name": "group_owner_id_user_id_fk", "tableFrom": "group", "tableTo": "user", - "columnsFrom": [ - "owner_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -881,12 +810,8 @@ "name": "group_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -894,12 +819,8 @@ "name": "group_mobile_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -909,9 +830,7 @@ "group_name_unique": { "name": "group_name_unique", "nullsNotDistinct": false, - "columns": [ - "name" - ] + "columns": ["name"] } }, "policies": {}, @@ -984,12 +903,8 @@ "name": "icon_icon_repository_id_iconRepository_id_fk", "tableFrom": "icon", "tableTo": "iconRepository", - "columnsFrom": [ - "icon_repository_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1029,12 +944,8 @@ "name": "integrationGroupPermissions_integration_id_integration_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1042,12 +953,8 @@ "name": "integrationGroupPermissions_group_id_group_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1055,11 +962,7 @@ "compositePrimaryKeys": { "integration_group_permission__pk": { "name": "integration_group_permission__pk", - "columns": [ - "integration_id", - "group_id", - "permission" - ] + "columns": ["integration_id", "group_id", "permission"] } }, "uniqueConstraints": {}, @@ -1090,12 +993,8 @@ "name": "integration_item_item_id_item_id_fk", "tableFrom": "integration_item", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1103,12 +1002,8 @@ "name": "integration_item_integration_id_integration_id_fk", "tableFrom": "integration_item", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1116,10 +1011,7 @@ "compositePrimaryKeys": { "integration_item_item_id_integration_id_pk": { "name": "integration_item_item_id_integration_id_pk", - "columns": [ - "item_id", - "integration_id" - ] + "columns": ["item_id", "integration_id"] } }, "uniqueConstraints": {}, @@ -1193,12 +1085,8 @@ "name": "integrationSecret_integration_id_integration_id_fk", "tableFrom": "integrationSecret", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1206,10 +1094,7 @@ "compositePrimaryKeys": { "integrationSecret_integration_id_kind_pk": { "name": "integrationSecret_integration_id_kind_pk", - "columns": [ - "integration_id", - "kind" - ] + "columns": ["integration_id", "kind"] } }, "uniqueConstraints": {}, @@ -1246,12 +1131,8 @@ "name": "integrationUserPermission_integration_id_integration_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1259,12 +1140,8 @@ "name": "integrationUserPermission_user_id_user_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1272,11 +1149,7 @@ "compositePrimaryKeys": { "integrationUserPermission_integration_id_user_id_permission_pk": { "name": "integrationUserPermission_integration_id_user_id_permission_pk", - "columns": [ - "integration_id", - "user_id", - "permission" - ] + "columns": ["integration_id", "user_id", "permission"] } }, "uniqueConstraints": {}, @@ -1341,12 +1214,8 @@ "name": "integration_app_id_app_id_fk", "tableFrom": "integration", "tableTo": "app", - "columnsFrom": [ - "app_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["app_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1392,12 +1261,8 @@ "name": "invite_creator_id_user_id_fk", "tableFrom": "invite", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1407,9 +1272,7 @@ "invite_token_unique": { "name": "invite_token_unique", "nullsNotDistinct": false, - "columns": [ - "token" - ] + "columns": ["token"] } }, "policies": {}, @@ -1469,12 +1332,8 @@ "name": "item_layout_item_id_item_id_fk", "tableFrom": "item_layout", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1482,12 +1341,8 @@ "name": "item_layout_section_id_section_id_fk", "tableFrom": "item_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1495,12 +1350,8 @@ "name": "item_layout_layout_id_layout_id_fk", "tableFrom": "item_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1508,11 +1359,7 @@ "compositePrimaryKeys": { "item_layout_item_id_section_id_layout_id_pk": { "name": "item_layout_item_id_section_id_layout_id_pk", - "columns": [ - "item_id", - "section_id", - "layout_id" - ] + "columns": ["item_id", "section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -1563,12 +1410,8 @@ "name": "item_board_id_board_id_fk", "tableFrom": "item", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1621,12 +1464,8 @@ "name": "layout_board_id_board_id_fk", "tableFrom": "layout", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1691,12 +1530,8 @@ "name": "media_creator_id_user_id_fk", "tableFrom": "media", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1798,12 +1633,8 @@ "name": "search_engine_integration_id_integration_id_fk", "tableFrom": "search_engine", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1813,9 +1644,7 @@ "search_engine_short_unique": { "name": "search_engine_short_unique", "nullsNotDistinct": false, - "columns": [ - "short" - ] + "columns": ["short"] } }, "policies": {}, @@ -1852,12 +1681,8 @@ "name": "section_collapse_state_user_id_user_id_fk", "tableFrom": "section_collapse_state", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1865,12 +1690,8 @@ "name": "section_collapse_state_section_id_section_id_fk", "tableFrom": "section_collapse_state", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1878,10 +1699,7 @@ "compositePrimaryKeys": { "section_collapse_state_user_id_section_id_pk": { "name": "section_collapse_state_user_id_section_id_pk", - "columns": [ - "user_id", - "section_id" - ] + "columns": ["user_id", "section_id"] } }, "uniqueConstraints": {}, @@ -1942,12 +1760,8 @@ "name": "section_layout_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1955,12 +1769,8 @@ "name": "section_layout_layout_id_layout_id_fk", "tableFrom": "section_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1968,12 +1778,8 @@ "name": "section_layout_parent_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "parent_section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1981,10 +1787,7 @@ "compositePrimaryKeys": { "section_layout_section_id_layout_id_pk": { "name": "section_layout_section_id_layout_id_pk", - "columns": [ - "section_id", - "layout_id" - ] + "columns": ["section_id", "layout_id"] } }, "uniqueConstraints": {}, @@ -2046,12 +1849,8 @@ "name": "section_board_id_board_id_fk", "tableFrom": "section", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2087,9 +1886,7 @@ "serverSetting_settingKey_unique": { "name": "serverSetting_settingKey_unique", "nullsNotDistinct": false, - "columns": [ - "setting_key" - ] + "columns": ["setting_key"] } }, "policies": {}, @@ -2141,12 +1938,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2278,12 +2071,8 @@ "name": "user_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2291,12 +2080,8 @@ "name": "user_mobile_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2304,12 +2089,8 @@ "name": "user_default_search_engine_id_search_engine_id_fk", "tableFrom": "user", "tableTo": "search_engine", - "columnsFrom": [ - "default_search_engine_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2348,10 +2129,7 @@ "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { "name": "verificationToken_identifier_token_pk", - "columns": [ - "identifier", - "token" - ] + "columns": ["identifier", "token"] } }, "uniqueConstraints": {}, @@ -2387,10 +2165,7 @@ "compositePrimaryKeys": { "trusted_certificate_hostname_hostname_thumbprint_pk": { "name": "trusted_certificate_hostname_hostname_thumbprint_pk", - "columns": [ - "hostname", - "thumbprint" - ] + "columns": ["hostname", "thumbprint"] } }, "uniqueConstraints": {}, @@ -2434,22 +2209,15 @@ "tableFrom": "widget_secret", "tableTo": "item", "schemaTo": "public", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "widget_secret_item_id_kind_pk": { - "columns": [ - "item_id", - "kind" - ], + "columns": ["item_id", "kind"], "name": "widget_secret_item_id_kind_pk" } }, diff --git a/packages/db/migrations/postgresql/meta/0013_snapshot.json b/packages/db/migrations/postgresql/meta/0013_snapshot.json new file mode 100644 index 000000000..215ff423a --- /dev/null +++ b/packages/db/migrations/postgresql/meta/0013_snapshot.json @@ -0,0 +1,2670 @@ +{ + "id": "ab2696e9-42d1-4aa0-bc60-b6d9fc50a7dc", + "prevId": "f1d7a91a-bf16-4f26-a0ae-ce77eab2a40e", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.account": { + "name": "account", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "provider_account_id": { + "name": "provider_account_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "userId_idx": { + "name": "userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.apiKey": { + "name": "apiKey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "api_key": { + "name": "api_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app": { + "name": "app", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "href": { + "name": "href", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ping_url": { + "name": "ping_url", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.assistant_configuration": { + "name": "assistant_configuration", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true, + "default": "'default'" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "web_search_enabled": { + "name": "web_search_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "provider": { + "name": "provider", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "default": "'openrouter'" + }, + "base_url": { + "name": "base_url", + "type": "varchar(2048)", + "primaryKey": false, + "notNull": true, + "default": "'https://openrouter.ai/api/v1'" + }, + "model_discovery_path": { + "name": "model_discovery_path", + "type": "varchar(512)", + "primaryKey": false, + "notNull": false, + "default": "'/models'" + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_headers": { + "name": "encrypted_headers", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model_id": { + "name": "model_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.assistant_message": { + "name": "assistant_message", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(128)", + "primaryKey": true, + "notNull": true + }, + "thread_id": { + "name": "thread_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "format": { + "name": "format", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "default": "'ai-sdk/v6'" + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "assistant_message__thread_id_created_at_idx": { + "name": "assistant_message__thread_id_created_at_idx", + "columns": [ + { + "expression": "thread_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "assistant_message_thread_id_assistant_thread_id_fk": { + "name": "assistant_message_thread_id_assistant_thread_id_fk", + "tableFrom": "assistant_message", + "tableTo": "assistant_thread", + "columnsFrom": ["thread_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.assistant_thread": { + "name": "assistant_thread", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "model_id": { + "name": "model_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "assistant_thread__user_id_updated_at_idx": { + "name": "assistant_thread__user_id_updated_at_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "assistant_thread_user_id_user_id_fk": { + "name": "assistant_thread_user_id_user_id_fk", + "tableFrom": "assistant_thread", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.boardGroupPermission": { + "name": "boardGroupPermission", + "schema": "", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.boardUserPermission": { + "name": "boardUserPermission", + "schema": "", + "columns": { + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.board": { + "name": "board", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "page_title": { + "name": "page_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "meta_title": { + "name": "meta_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "logo_image_url": { + "name": "logo_image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "favicon_image_url": { + "name": "favicon_image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "background_image_url": { + "name": "background_image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "background_image_attachment": { + "name": "background_image_attachment", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'fixed'" + }, + "background_image_repeat": { + "name": "background_image_repeat", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'no-repeat'" + }, + "background_image_size": { + "name": "background_image_size", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'cover'" + }, + "primary_color": { + "name": "primary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'#fa5252'" + }, + "secondary_color": { + "name": "secondary_color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'#fd7e14'" + }, + "opacity": { + "name": "opacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 100 + }, + "custom_css": { + "name": "custom_css", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "icon_color": { + "name": "icon_color", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "item_radius": { + "name": "item_radius", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'lg'" + }, + "disable_status": { + "name": "disable_status", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "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": {}, + "uniqueConstraints": { + "board_name_unique": { + "name": "board_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.cron_job_configuration": { + "name": "cron_job_configuration", + "schema": "", + "columns": { + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": true, + "notNull": true + }, + "cron_expression": { + "name": "cron_expression", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_widget_v2_definition": { + "name": "custom_widget_v2_definition", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sources": { + "name": "sources", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "requests": { + "name": "requests", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "template": { + "name": "template", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "custom_widget_v2_definition_creator_id_user_id_fk": { + "name": "custom_widget_v2_definition_creator_id_user_id_fk", + "tableFrom": "custom_widget_v2_definition", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_widget_v2_secret": { + "name": "custom_widget_v2_secret", + "schema": "", + "columns": { + "source_id": { + "name": "source_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "encrypted_value": { + "name": "encrypted_value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "definition_id": { + "name": "definition_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "custom_widget_v2_secret_definition_id_fk": { + "name": "custom_widget_v2_secret_definition_id_fk", + "tableFrom": "custom_widget_v2_secret", + "tableTo": "custom_widget_v2_definition", + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "custom_widget_v2_secret_definition_id_source_id_kind_pk": { + "name": "custom_widget_v2_secret_definition_id_source_id_kind_pk", + "columns": ["definition_id", "source_id", "kind"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.groupMember": { + "name": "groupMember", + "schema": "", + "columns": { + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.groupPermission": { + "name": "groupPermission", + "schema": "", + "columns": { + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.group": { + "name": "group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "owner_id": { + "name": "owner_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "home_board_id": { + "name": "home_board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "mobile_home_board_id": { + "name": "mobile_home_board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "position": { + "name": "position", + "type": "smallint", + "primaryKey": false, + "notNull": true + } + }, + "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" + }, + "group_home_board_id_board_id_fk": { + "name": "group_home_board_id_board_id_fk", + "tableFrom": "group", + "tableTo": "board", + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "group_mobile_home_board_id_board_id_fk": { + "name": "group_mobile_home_board_id_board_id_fk", + "tableFrom": "group", + "tableTo": "board", + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "group_name_unique": { + "name": "group_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.iconRepository": { + "name": "iconRepository", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "varchar(150)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.icon": { + "name": "icon", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(250)", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "checksum": { + "name": "checksum", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "icon_repository_id": { + "name": "icon_repository_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integrationGroupPermissions": { + "name": "integrationGroupPermissions", + "schema": "", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integration_item": { + "name": "integration_item", + "schema": "", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integrationSecret": { + "name": "integrationSecret", + "schema": "", + "columns": { + "kind": { + "name": "kind", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "integration_secret__kind_idx": { + "name": "integration_secret__kind_idx", + "columns": [ + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "integration_secret__updated_at_idx": { + "name": "integration_secret__updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integrationUserPermission": { + "name": "integrationUserPermission", + "schema": "", + "columns": { + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.integration": { + "name": "integration", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "app_id": { + "name": "app_id", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": [ + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "integration_app_id_app_id_fk": { + "name": "integration_app_id_app_id_fk", + "tableFrom": "integration", + "tableTo": "app", + "columnsFrom": ["app_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invite": { + "name": "invite", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true + }, + "expiration_date": { + "name": "expiration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + } + }, + "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": {}, + "uniqueConstraints": { + "invite_token_unique": { + "name": "invite_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.item_layout": { + "name": "item_layout", + "schema": "", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "layout_id": { + "name": "layout_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "item_layout_item_id_item_id_fk": { + "name": "item_layout_item_id_item_id_fk", + "tableFrom": "item_layout", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "item_layout_section_id_section_id_fk": { + "name": "item_layout_section_id_section_id_fk", + "tableFrom": "item_layout", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "item_layout_layout_id_layout_id_fk": { + "name": "item_layout_layout_id_layout_id_fk", + "tableFrom": "item_layout", + "tableTo": "layout", + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_layout_item_id_section_id_layout_id_pk": { + "name": "item_layout_item_id_section_id_layout_id_pk", + "columns": ["item_id", "section_id", "layout_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.item": { + "name": "item", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'{\"json\": {}}'" + }, + "advanced_options": { + "name": "advanced_options", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'{\"json\": {}}'" + } + }, + "indexes": {}, + "foreignKeys": { + "item_board_id_board_id_fk": { + "name": "item_board_id_board_id_fk", + "tableFrom": "item", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.layout": { + "name": "layout", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true + }, + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "column_count": { + "name": "column_count", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "left_gutter_column_count": { + "name": "left_gutter_column_count", + "type": "smallint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "right_gutter_column_count": { + "name": "right_gutter_column_count", + "type": "smallint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "breakpoint": { + "name": "breakpoint", + "type": "smallint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "role": { + "name": "role", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true, + "default": "'custom'" + } + }, + "indexes": {}, + "foreignKeys": { + "layout_board_id_board_id_fk": { + "name": "layout_board_id_board_id_fk", + "tableFrom": "layout", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_widget_definition": { + "name": "custom_widget_definition", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auth_type": { + "name": "auth_type", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "header_name": { + "name": "header_name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "method": { + "name": "method", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true, + "default": "'GET'" + }, + "request_body": { + "name": "request_body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_type": { + "name": "display_type", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true, + "default": "'singleValue'" + }, + "display_config": { + "name": "display_config", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'{\"json\": {}}'" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "custom_widget_definition_creator_id_user_id_fk": { + "name": "custom_widget_definition_creator_id_user_id_fk", + "tableFrom": "custom_widget_definition", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_widget_secret": { + "name": "custom_widget_secret", + "schema": "", + "columns": { + "kind": { + "name": "kind", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "definition_id": { + "name": "definition_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "custom_widget_secret_definition_id_custom_widget_definition_id_fk": { + "name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk", + "tableFrom": "custom_widget_secret", + "tableTo": "custom_widget_definition", + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "custom_widget_secret_definition_id_kind_pk": { + "name": "custom_widget_secret_definition_id_kind_pk", + "columns": ["definition_id", "kind"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.media": { + "name": "media", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "bytea", + "primaryKey": false, + "notNull": true + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "creator_id": { + "name": "creator_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": 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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.onboarding": { + "name": "onboarding", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "step": { + "name": "step", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "previous_step": { + "name": "previous_step", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.search_engine": { + "name": "search_engine", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "short": { + "name": "short", + "type": "varchar(8)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "url_template": { + "name": "url_template", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "default": "'generic'" + }, + "integration_id": { + "name": "integration_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": 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": { + "search_engine_short_unique": { + "name": "search_engine_short_unique", + "nullsNotDistinct": false, + "columns": ["short"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.section_collapse_state": { + "name": "section_collapse_state", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "collapsed": { + "name": "collapsed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_collapse_state_user_id_user_id_fk": { + "name": "section_collapse_state_user_id_user_id_fk", + "tableFrom": "section_collapse_state", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_collapse_state_section_id_section_id_fk": { + "name": "section_collapse_state_section_id_section_id_fk", + "tableFrom": "section_collapse_state", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_collapse_state_user_id_section_id_pk": { + "name": "section_collapse_state_user_id_section_id_pk", + "columns": ["user_id", "section_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.section_layout": { + "name": "section_layout", + "schema": "", + "columns": { + "section_id": { + "name": "section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "layout_id": { + "name": "layout_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "section_layout_section_id_section_id_fk": { + "name": "section_layout_section_id_section_id_fk", + "tableFrom": "section_layout", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_layout_layout_id_layout_id_fk": { + "name": "section_layout_layout_id_layout_id_fk", + "tableFrom": "section_layout", + "tableTo": "layout", + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_layout_parent_section_id_section_id_fk": { + "name": "section_layout_parent_section_id_section_id_fk", + "tableFrom": "section_layout", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_layout_section_id_layout_id_pk": { + "name": "section_layout_section_id_layout_id_pk", + "columns": ["section_id", "layout_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.section": { + "name": "section", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "board_id": { + "name": "board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "x_offset": { + "name": "x_offset", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'{\"json\": {}}'" + } + }, + "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" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.serverSetting": { + "name": "serverSetting", + "schema": "", + "columns": { + "setting_key": { + "name": "setting_key", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'{\"json\": {}}'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "serverSetting_settingKey_unique": { + "name": "serverSetting_settingKey_unique", + "nullsNotDistinct": false, + "columns": ["setting_key"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "session_token": { + "name": "session_token", + "type": "varchar(512)", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "user_id_idx": { + "name": "user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.trusted_certificate_hostname": { + "name": "trusted_certificate_hostname", + "schema": "", + "columns": { + "hostname": { + "name": "hostname", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "thumbprint": { + "name": "thumbprint", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true + }, + "certificate": { + "name": "certificate", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "trusted_certificate_hostname_hostname_thumbprint_pk": { + "name": "trusted_certificate_hostname_hostname_thumbprint_pk", + "columns": ["hostname", "thumbprint"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_verified": { + "name": "email_verified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true, + "default": "'credentials'" + }, + "home_board_id": { + "name": "home_board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "mobile_home_board_id": { + "name": "mobile_home_board_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "default_search_engine_id": { + "name": "default_search_engine_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "open_search_in_new_tab": { + "name": "open_search_in_new_tab", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "ddg_bangs": { + "name": "ddg_bangs", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "color_scheme": { + "name": "color_scheme", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "default": "'dark'" + }, + "first_day_of_week": { + "name": "first_day_of_week", + "type": "smallint", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "ping_icons_enabled": { + "name": "ping_icons_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enable_right_click_on_widgets": { + "name": "enable_right_click_on_widgets", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "completed_manage_tour": { + "name": "completed_manage_tour", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "completed_board_tour": { + "name": "completed_board_tour", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "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": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "varchar(512)", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": ["identifier", "token"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.widget_secret": { + "name": "widget_secret", + "schema": "", + "columns": { + "item_id": { + "name": "item_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "widget_secret_item_id_item_id_fk": { + "name": "widget_secret_item_id_item_id_fk", + "tableFrom": "widget_secret", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "widget_secret_item_id_kind_pk": { + "name": "widget_secret_item_id_kind_pk", + "columns": ["item_id", "kind"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/packages/db/migrations/sqlite/0042_add_layout_role.sql b/packages/db/migrations/sqlite/0042_add_layout_role.sql deleted file mode 100644 index d0a800e0d..000000000 --- a/packages/db/migrations/sqlite/0042_add_layout_role.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `layout` ADD `role` text DEFAULT 'custom' NOT NULL; diff --git a/packages/db/migrations/sqlite/0043_swift_silver_samurai.sql b/packages/db/migrations/sqlite/0043_swift_silver_samurai.sql deleted file mode 100644 index 6104ecd11..000000000 --- a/packages/db/migrations/sqlite/0043_swift_silver_samurai.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `assistant_configuration` ADD `web_search_enabled` integer DEFAULT false NOT NULL; \ No newline at end of file diff --git a/packages/db/migrations/sqlite/meta/0038_snapshot.json b/packages/db/migrations/sqlite/meta/0038_snapshot.json index a000c93d9..0535c6bc5 100644 --- a/packages/db/migrations/sqlite/meta/0038_snapshot.json +++ b/packages/db/migrations/sqlite/meta/0038_snapshot.json @@ -88,9 +88,7 @@ "indexes": { "userId_idx": { "name": "userId_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -99,22 +97,15 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "account_provider_provider_account_id_pk": { - "columns": [ - "provider", - "provider_account_id" - ], + "columns": ["provider", "provider_account_id"], "name": "account_provider_provider_account_id_pk" } }, @@ -152,12 +143,8 @@ "name": "apiKey_user_id_user_id_fk", "tableFrom": "apiKey", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -249,12 +236,8 @@ "name": "boardGroupPermission_board_id_board_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -262,23 +245,15 @@ "name": "boardGroupPermission_group_id_group_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "boardGroupPermission_board_id_group_id_permission_pk": { - "columns": [ - "board_id", - "group_id", - "permission" - ], + "columns": ["board_id", "group_id", "permission"], "name": "boardGroupPermission_board_id_group_id_permission_pk" } }, @@ -316,12 +291,8 @@ "name": "boardUserPermission_board_id_board_id_fk", "tableFrom": "boardUserPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -329,23 +300,15 @@ "name": "boardUserPermission_user_id_user_id_fk", "tableFrom": "boardUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "boardUserPermission_board_id_user_id_permission_pk": { - "columns": [ - "board_id", - "user_id", - "permission" - ], + "columns": ["board_id", "user_id", "permission"], "name": "boardUserPermission_board_id_user_id_permission_pk" } }, @@ -501,9 +464,7 @@ "indexes": { "board_name_unique": { "name": "board_name_unique", - "columns": [ - "name" - ], + "columns": ["name"], "isUnique": true } }, @@ -512,12 +473,8 @@ "name": "board_creator_id_user_id_fk", "tableFrom": "board", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -679,12 +636,8 @@ "name": "custom_widget_definition_creator_id_user_id_fk", "tableFrom": "custom_widget_definition", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -731,22 +684,15 @@ "name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk", "tableFrom": "custom_widget_secret", "tableTo": "custom_widget_definition", - "columnsFrom": [ - "definition_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "custom_widget_secret_definition_id_kind_pk": { - "columns": [ - "definition_id", - "kind" - ], + "columns": ["definition_id", "kind"], "name": "custom_widget_secret_definition_id_kind_pk" } }, @@ -777,12 +723,8 @@ "name": "groupMember_group_id_group_id_fk", "tableFrom": "groupMember", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -790,22 +732,15 @@ "name": "groupMember_user_id_user_id_fk", "tableFrom": "groupMember", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "groupMember_group_id_user_id_pk": { - "columns": [ - "group_id", - "user_id" - ], + "columns": ["group_id", "user_id"], "name": "groupMember_group_id_user_id_pk" } }, @@ -836,12 +771,8 @@ "name": "groupPermission_group_id_group_id_fk", "tableFrom": "groupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -899,9 +830,7 @@ "indexes": { "group_name_unique": { "name": "group_name_unique", - "columns": [ - "name" - ], + "columns": ["name"], "isUnique": true } }, @@ -910,12 +839,8 @@ "name": "group_owner_id_user_id_fk", "tableFrom": "group", "tableTo": "user", - "columnsFrom": [ - "owner_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -923,12 +848,8 @@ "name": "group_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -936,12 +857,8 @@ "name": "group_mobile_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1019,12 +936,8 @@ "name": "icon_icon_repository_id_iconRepository_id_fk", "tableFrom": "icon", "tableTo": "iconRepository", - "columnsFrom": [ - "icon_repository_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1064,12 +977,8 @@ "name": "integrationGroupPermissions_integration_id_integration_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1077,23 +986,15 @@ "name": "integrationGroupPermissions_group_id_group_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integrationGroupPermissions_integration_id_group_id_permission_pk": { - "columns": [ - "integration_id", - "group_id", - "permission" - ], + "columns": ["integration_id", "group_id", "permission"], "name": "integrationGroupPermissions_integration_id_group_id_permission_pk" } }, @@ -1124,12 +1025,8 @@ "name": "integration_item_item_id_item_id_fk", "tableFrom": "integration_item", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1137,22 +1034,15 @@ "name": "integration_item_integration_id_integration_id_fk", "tableFrom": "integration_item", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integration_item_item_id_integration_id_pk": { - "columns": [ - "item_id", - "integration_id" - ], + "columns": ["item_id", "integration_id"], "name": "integration_item_item_id_integration_id_pk" } }, @@ -1194,16 +1084,12 @@ "indexes": { "integration_secret__kind_idx": { "name": "integration_secret__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false }, "integration_secret__updated_at_idx": { "name": "integration_secret__updated_at_idx", - "columns": [ - "updated_at" - ], + "columns": ["updated_at"], "isUnique": false } }, @@ -1212,22 +1098,15 @@ "name": "integrationSecret_integration_id_integration_id_fk", "tableFrom": "integrationSecret", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integrationSecret_integration_id_kind_pk": { - "columns": [ - "integration_id", - "kind" - ], + "columns": ["integration_id", "kind"], "name": "integrationSecret_integration_id_kind_pk" } }, @@ -1265,12 +1144,8 @@ "name": "integrationUserPermission_integration_id_integration_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1278,23 +1153,15 @@ "name": "integrationUserPermission_user_id_user_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integrationUserPermission_integration_id_user_id_permission_pk": { - "columns": [ - "integration_id", - "user_id", - "permission" - ], + "columns": ["integration_id", "user_id", "permission"], "name": "integrationUserPermission_integration_id_user_id_permission_pk" } }, @@ -1343,9 +1210,7 @@ "indexes": { "integration__kind_idx": { "name": "integration__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false } }, @@ -1354,12 +1219,8 @@ "name": "integration_app_id_app_id_fk", "tableFrom": "integration", "tableTo": "app", - "columnsFrom": [ - "app_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["app_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1403,9 +1264,7 @@ "indexes": { "invite_token_unique": { "name": "invite_token_unique", - "columns": [ - "token" - ], + "columns": ["token"], "isUnique": true } }, @@ -1414,12 +1273,8 @@ "name": "invite_creator_id_user_id_fk", "tableFrom": "invite", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1487,12 +1342,8 @@ "name": "item_layout_item_id_item_id_fk", "tableFrom": "item_layout", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1500,12 +1351,8 @@ "name": "item_layout_section_id_section_id_fk", "tableFrom": "item_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1513,23 +1360,15 @@ "name": "item_layout_layout_id_layout_id_fk", "tableFrom": "item_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "item_layout_item_id_section_id_layout_id_pk": { - "columns": [ - "item_id", - "section_id", - "layout_id" - ], + "columns": ["item_id", "section_id", "layout_id"], "name": "item_layout_item_id_section_id_layout_id_pk" } }, @@ -1583,12 +1422,8 @@ "name": "item_board_id_board_id_fk", "tableFrom": "item", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1643,12 +1478,8 @@ "name": "layout_board_id_board_id_fk", "tableFrom": "layout", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1717,12 +1548,8 @@ "name": "media_creator_id_user_id_fk", "tableFrom": "media", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1826,9 +1653,7 @@ "indexes": { "search_engine_short_unique": { "name": "search_engine_short_unique", - "columns": [ - "short" - ], + "columns": ["short"], "isUnique": true } }, @@ -1837,12 +1662,8 @@ "name": "search_engine_integration_id_integration_id_fk", "tableFrom": "search_engine", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1883,12 +1704,8 @@ "name": "section_collapse_state_user_id_user_id_fk", "tableFrom": "section_collapse_state", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1896,22 +1713,15 @@ "name": "section_collapse_state_section_id_section_id_fk", "tableFrom": "section_collapse_state", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "section_collapse_state_user_id_section_id_pk": { - "columns": [ - "user_id", - "section_id" - ], + "columns": ["user_id", "section_id"], "name": "section_collapse_state_user_id_section_id_pk" } }, @@ -1977,12 +1787,8 @@ "name": "section_layout_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1990,12 +1796,8 @@ "name": "section_layout_layout_id_layout_id_fk", "tableFrom": "section_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2003,22 +1805,15 @@ "name": "section_layout_parent_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "parent_section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "section_layout_section_id_layout_id_pk": { - "columns": [ - "section_id", - "layout_id" - ], + "columns": ["section_id", "layout_id"], "name": "section_layout_section_id_layout_id_pk" } }, @@ -2085,12 +1880,8 @@ "name": "section_board_id_board_id_fk", "tableFrom": "section", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2121,9 +1912,7 @@ "indexes": { "serverSetting_settingKey_unique": { "name": "serverSetting_settingKey_unique", - "columns": [ - "setting_key" - ], + "columns": ["setting_key"], "isUnique": true } }, @@ -2160,9 +1949,7 @@ "indexes": { "user_id_idx": { "name": "user_id_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -2171,12 +1958,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2214,10 +1997,7 @@ "foreignKeys": {}, "compositePrimaryKeys": { "trusted_certificate_hostname_hostname_thumbprint_pk": { - "columns": [ - "hostname", - "thumbprint" - ], + "columns": ["hostname", "thumbprint"], "name": "trusted_certificate_hostname_hostname_thumbprint_pk" } }, @@ -2361,12 +2141,8 @@ "name": "user_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2374,12 +2150,8 @@ "name": "user_mobile_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2387,12 +2159,8 @@ "name": "user_default_search_engine_id_search_engine_id_fk", "tableFrom": "user", "tableTo": "search_engine", - "columnsFrom": [ - "default_search_engine_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2430,10 +2198,7 @@ "foreignKeys": {}, "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { - "columns": [ - "identifier", - "token" - ], + "columns": ["identifier", "token"], "name": "verificationToken_identifier_token_pk" } }, @@ -2451,4 +2216,4 @@ "internal": { "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/db/migrations/sqlite/meta/0039_snapshot.json b/packages/db/migrations/sqlite/meta/0039_snapshot.json index 2b5d2cf26..cc4de72de 100644 --- a/packages/db/migrations/sqlite/meta/0039_snapshot.json +++ b/packages/db/migrations/sqlite/meta/0039_snapshot.json @@ -88,9 +88,7 @@ "indexes": { "userId_idx": { "name": "userId_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -99,22 +97,15 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "account_provider_provider_account_id_pk": { - "columns": [ - "provider", - "provider_account_id" - ], + "columns": ["provider", "provider_account_id"], "name": "account_provider_provider_account_id_pk" } }, @@ -152,12 +143,8 @@ "name": "apiKey_user_id_user_id_fk", "tableFrom": "apiKey", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -249,12 +236,8 @@ "name": "boardGroupPermission_board_id_board_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -262,23 +245,15 @@ "name": "boardGroupPermission_group_id_group_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "boardGroupPermission_board_id_group_id_permission_pk": { - "columns": [ - "board_id", - "group_id", - "permission" - ], + "columns": ["board_id", "group_id", "permission"], "name": "boardGroupPermission_board_id_group_id_permission_pk" } }, @@ -316,12 +291,8 @@ "name": "boardUserPermission_board_id_board_id_fk", "tableFrom": "boardUserPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -329,23 +300,15 @@ "name": "boardUserPermission_user_id_user_id_fk", "tableFrom": "boardUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "boardUserPermission_board_id_user_id_permission_pk": { - "columns": [ - "board_id", - "user_id", - "permission" - ], + "columns": ["board_id", "user_id", "permission"], "name": "boardUserPermission_board_id_user_id_permission_pk" } }, @@ -501,9 +464,7 @@ "indexes": { "board_name_unique": { "name": "board_name_unique", - "columns": [ - "name" - ], + "columns": ["name"], "isUnique": true } }, @@ -512,12 +473,8 @@ "name": "board_creator_id_user_id_fk", "tableFrom": "board", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -680,12 +637,8 @@ "name": "custom_widget_definition_creator_id_user_id_fk", "tableFrom": "custom_widget_definition", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -732,22 +685,15 @@ "name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk", "tableFrom": "custom_widget_secret", "tableTo": "custom_widget_definition", - "columnsFrom": [ - "definition_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "custom_widget_secret_definition_id_kind_pk": { - "columns": [ - "definition_id", - "kind" - ], + "columns": ["definition_id", "kind"], "name": "custom_widget_secret_definition_id_kind_pk" } }, @@ -778,12 +724,8 @@ "name": "groupMember_group_id_group_id_fk", "tableFrom": "groupMember", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -791,22 +733,15 @@ "name": "groupMember_user_id_user_id_fk", "tableFrom": "groupMember", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "groupMember_group_id_user_id_pk": { - "columns": [ - "group_id", - "user_id" - ], + "columns": ["group_id", "user_id"], "name": "groupMember_group_id_user_id_pk" } }, @@ -837,12 +772,8 @@ "name": "groupPermission_group_id_group_id_fk", "tableFrom": "groupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -900,9 +831,7 @@ "indexes": { "group_name_unique": { "name": "group_name_unique", - "columns": [ - "name" - ], + "columns": ["name"], "isUnique": true } }, @@ -911,12 +840,8 @@ "name": "group_owner_id_user_id_fk", "tableFrom": "group", "tableTo": "user", - "columnsFrom": [ - "owner_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -924,12 +849,8 @@ "name": "group_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -937,12 +858,8 @@ "name": "group_mobile_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1020,12 +937,8 @@ "name": "icon_icon_repository_id_iconRepository_id_fk", "tableFrom": "icon", "tableTo": "iconRepository", - "columnsFrom": [ - "icon_repository_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1065,12 +978,8 @@ "name": "integrationGroupPermissions_integration_id_integration_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1078,23 +987,15 @@ "name": "integrationGroupPermissions_group_id_group_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integrationGroupPermissions_integration_id_group_id_permission_pk": { - "columns": [ - "integration_id", - "group_id", - "permission" - ], + "columns": ["integration_id", "group_id", "permission"], "name": "integrationGroupPermissions_integration_id_group_id_permission_pk" } }, @@ -1125,12 +1026,8 @@ "name": "integration_item_item_id_item_id_fk", "tableFrom": "integration_item", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1138,22 +1035,15 @@ "name": "integration_item_integration_id_integration_id_fk", "tableFrom": "integration_item", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integration_item_item_id_integration_id_pk": { - "columns": [ - "item_id", - "integration_id" - ], + "columns": ["item_id", "integration_id"], "name": "integration_item_item_id_integration_id_pk" } }, @@ -1195,16 +1085,12 @@ "indexes": { "integration_secret__kind_idx": { "name": "integration_secret__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false }, "integration_secret__updated_at_idx": { "name": "integration_secret__updated_at_idx", - "columns": [ - "updated_at" - ], + "columns": ["updated_at"], "isUnique": false } }, @@ -1213,22 +1099,15 @@ "name": "integrationSecret_integration_id_integration_id_fk", "tableFrom": "integrationSecret", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integrationSecret_integration_id_kind_pk": { - "columns": [ - "integration_id", - "kind" - ], + "columns": ["integration_id", "kind"], "name": "integrationSecret_integration_id_kind_pk" } }, @@ -1266,12 +1145,8 @@ "name": "integrationUserPermission_integration_id_integration_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1279,23 +1154,15 @@ "name": "integrationUserPermission_user_id_user_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integrationUserPermission_integration_id_user_id_permission_pk": { - "columns": [ - "integration_id", - "user_id", - "permission" - ], + "columns": ["integration_id", "user_id", "permission"], "name": "integrationUserPermission_integration_id_user_id_permission_pk" } }, @@ -1344,9 +1211,7 @@ "indexes": { "integration__kind_idx": { "name": "integration__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false } }, @@ -1355,12 +1220,8 @@ "name": "integration_app_id_app_id_fk", "tableFrom": "integration", "tableTo": "app", - "columnsFrom": [ - "app_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["app_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1404,9 +1265,7 @@ "indexes": { "invite_token_unique": { "name": "invite_token_unique", - "columns": [ - "token" - ], + "columns": ["token"], "isUnique": true } }, @@ -1415,12 +1274,8 @@ "name": "invite_creator_id_user_id_fk", "tableFrom": "invite", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1488,12 +1343,8 @@ "name": "item_layout_item_id_item_id_fk", "tableFrom": "item_layout", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1501,12 +1352,8 @@ "name": "item_layout_section_id_section_id_fk", "tableFrom": "item_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1514,23 +1361,15 @@ "name": "item_layout_layout_id_layout_id_fk", "tableFrom": "item_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "item_layout_item_id_section_id_layout_id_pk": { - "columns": [ - "item_id", - "section_id", - "layout_id" - ], + "columns": ["item_id", "section_id", "layout_id"], "name": "item_layout_item_id_section_id_layout_id_pk" } }, @@ -1584,12 +1423,8 @@ "name": "item_board_id_board_id_fk", "tableFrom": "item", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1644,12 +1479,8 @@ "name": "layout_board_id_board_id_fk", "tableFrom": "layout", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1718,12 +1549,8 @@ "name": "media_creator_id_user_id_fk", "tableFrom": "media", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1827,9 +1654,7 @@ "indexes": { "search_engine_short_unique": { "name": "search_engine_short_unique", - "columns": [ - "short" - ], + "columns": ["short"], "isUnique": true } }, @@ -1838,12 +1663,8 @@ "name": "search_engine_integration_id_integration_id_fk", "tableFrom": "search_engine", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1884,12 +1705,8 @@ "name": "section_collapse_state_user_id_user_id_fk", "tableFrom": "section_collapse_state", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1897,22 +1714,15 @@ "name": "section_collapse_state_section_id_section_id_fk", "tableFrom": "section_collapse_state", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "section_collapse_state_user_id_section_id_pk": { - "columns": [ - "user_id", - "section_id" - ], + "columns": ["user_id", "section_id"], "name": "section_collapse_state_user_id_section_id_pk" } }, @@ -1978,12 +1788,8 @@ "name": "section_layout_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1991,12 +1797,8 @@ "name": "section_layout_layout_id_layout_id_fk", "tableFrom": "section_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2004,22 +1806,15 @@ "name": "section_layout_parent_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "parent_section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "section_layout_section_id_layout_id_pk": { - "columns": [ - "section_id", - "layout_id" - ], + "columns": ["section_id", "layout_id"], "name": "section_layout_section_id_layout_id_pk" } }, @@ -2086,12 +1881,8 @@ "name": "section_board_id_board_id_fk", "tableFrom": "section", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2122,9 +1913,7 @@ "indexes": { "serverSetting_settingKey_unique": { "name": "serverSetting_settingKey_unique", - "columns": [ - "setting_key" - ], + "columns": ["setting_key"], "isUnique": true } }, @@ -2161,9 +1950,7 @@ "indexes": { "user_id_idx": { "name": "user_id_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -2172,12 +1959,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2215,10 +1998,7 @@ "foreignKeys": {}, "compositePrimaryKeys": { "trusted_certificate_hostname_hostname_thumbprint_pk": { - "columns": [ - "hostname", - "thumbprint" - ], + "columns": ["hostname", "thumbprint"], "name": "trusted_certificate_hostname_hostname_thumbprint_pk" } }, @@ -2362,12 +2142,8 @@ "name": "user_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2375,12 +2151,8 @@ "name": "user_mobile_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2388,12 +2160,8 @@ "name": "user_default_search_engine_id_search_engine_id_fk", "tableFrom": "user", "tableTo": "search_engine", - "columnsFrom": [ - "default_search_engine_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2431,10 +2199,7 @@ "foreignKeys": {}, "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { - "columns": [ - "identifier", - "token" - ], + "columns": ["identifier", "token"], "name": "verificationToken_identifier_token_pk" } }, diff --git a/packages/db/migrations/sqlite/meta/0040_snapshot.json b/packages/db/migrations/sqlite/meta/0040_snapshot.json index 9f0bc677e..b7da34135 100644 --- a/packages/db/migrations/sqlite/meta/0040_snapshot.json +++ b/packages/db/migrations/sqlite/meta/0040_snapshot.json @@ -88,9 +88,7 @@ "indexes": { "userId_idx": { "name": "userId_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -99,22 +97,15 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "account_provider_provider_account_id_pk": { - "columns": [ - "provider", - "provider_account_id" - ], + "columns": ["provider", "provider_account_id"], "name": "account_provider_provider_account_id_pk" } }, @@ -152,12 +143,8 @@ "name": "apiKey_user_id_user_id_fk", "tableFrom": "apiKey", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -249,12 +236,8 @@ "name": "boardGroupPermission_board_id_board_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -262,23 +245,15 @@ "name": "boardGroupPermission_group_id_group_id_fk", "tableFrom": "boardGroupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "boardGroupPermission_board_id_group_id_permission_pk": { - "columns": [ - "board_id", - "group_id", - "permission" - ], + "columns": ["board_id", "group_id", "permission"], "name": "boardGroupPermission_board_id_group_id_permission_pk" } }, @@ -316,12 +291,8 @@ "name": "boardUserPermission_board_id_board_id_fk", "tableFrom": "boardUserPermission", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -329,23 +300,15 @@ "name": "boardUserPermission_user_id_user_id_fk", "tableFrom": "boardUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "boardUserPermission_board_id_user_id_permission_pk": { - "columns": [ - "board_id", - "user_id", - "permission" - ], + "columns": ["board_id", "user_id", "permission"], "name": "boardUserPermission_board_id_user_id_permission_pk" } }, @@ -501,9 +464,7 @@ "indexes": { "board_name_unique": { "name": "board_name_unique", - "columns": [ - "name" - ], + "columns": ["name"], "isUnique": true } }, @@ -512,12 +473,8 @@ "name": "board_creator_id_user_id_fk", "tableFrom": "board", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -680,12 +637,8 @@ "name": "custom_widget_definition_creator_id_user_id_fk", "tableFrom": "custom_widget_definition", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -732,22 +685,15 @@ "name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk", "tableFrom": "custom_widget_secret", "tableTo": "custom_widget_definition", - "columnsFrom": [ - "definition_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "custom_widget_secret_definition_id_kind_pk": { - "columns": [ - "definition_id", - "kind" - ], + "columns": ["definition_id", "kind"], "name": "custom_widget_secret_definition_id_kind_pk" } }, @@ -778,12 +724,8 @@ "name": "groupMember_group_id_group_id_fk", "tableFrom": "groupMember", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -791,22 +733,15 @@ "name": "groupMember_user_id_user_id_fk", "tableFrom": "groupMember", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "groupMember_group_id_user_id_pk": { - "columns": [ - "group_id", - "user_id" - ], + "columns": ["group_id", "user_id"], "name": "groupMember_group_id_user_id_pk" } }, @@ -837,12 +772,8 @@ "name": "groupPermission_group_id_group_id_fk", "tableFrom": "groupPermission", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -900,9 +831,7 @@ "indexes": { "group_name_unique": { "name": "group_name_unique", - "columns": [ - "name" - ], + "columns": ["name"], "isUnique": true } }, @@ -911,12 +840,8 @@ "name": "group_owner_id_user_id_fk", "tableFrom": "group", "tableTo": "user", - "columnsFrom": [ - "owner_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -924,12 +849,8 @@ "name": "group_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -937,12 +858,8 @@ "name": "group_mobile_home_board_id_board_id_fk", "tableFrom": "group", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1020,12 +937,8 @@ "name": "icon_icon_repository_id_iconRepository_id_fk", "tableFrom": "icon", "tableTo": "iconRepository", - "columnsFrom": [ - "icon_repository_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["icon_repository_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1065,12 +978,8 @@ "name": "integrationGroupPermissions_integration_id_integration_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1078,23 +987,15 @@ "name": "integrationGroupPermissions_group_id_group_id_fk", "tableFrom": "integrationGroupPermissions", "tableTo": "group", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["group_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integrationGroupPermissions_integration_id_group_id_permission_pk": { - "columns": [ - "integration_id", - "group_id", - "permission" - ], + "columns": ["integration_id", "group_id", "permission"], "name": "integrationGroupPermissions_integration_id_group_id_permission_pk" } }, @@ -1125,12 +1026,8 @@ "name": "integration_item_item_id_item_id_fk", "tableFrom": "integration_item", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1138,22 +1035,15 @@ "name": "integration_item_integration_id_integration_id_fk", "tableFrom": "integration_item", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integration_item_item_id_integration_id_pk": { - "columns": [ - "item_id", - "integration_id" - ], + "columns": ["item_id", "integration_id"], "name": "integration_item_item_id_integration_id_pk" } }, @@ -1195,16 +1085,12 @@ "indexes": { "integration_secret__kind_idx": { "name": "integration_secret__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false }, "integration_secret__updated_at_idx": { "name": "integration_secret__updated_at_idx", - "columns": [ - "updated_at" - ], + "columns": ["updated_at"], "isUnique": false } }, @@ -1213,22 +1099,15 @@ "name": "integrationSecret_integration_id_integration_id_fk", "tableFrom": "integrationSecret", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integrationSecret_integration_id_kind_pk": { - "columns": [ - "integration_id", - "kind" - ], + "columns": ["integration_id", "kind"], "name": "integrationSecret_integration_id_kind_pk" } }, @@ -1266,12 +1145,8 @@ "name": "integrationUserPermission_integration_id_integration_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1279,23 +1154,15 @@ "name": "integrationUserPermission_user_id_user_id_fk", "tableFrom": "integrationUserPermission", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "integrationUserPermission_integration_id_user_id_permission_pk": { - "columns": [ - "integration_id", - "user_id", - "permission" - ], + "columns": ["integration_id", "user_id", "permission"], "name": "integrationUserPermission_integration_id_user_id_permission_pk" } }, @@ -1344,9 +1211,7 @@ "indexes": { "integration__kind_idx": { "name": "integration__kind_idx", - "columns": [ - "kind" - ], + "columns": ["kind"], "isUnique": false } }, @@ -1355,12 +1220,8 @@ "name": "integration_app_id_app_id_fk", "tableFrom": "integration", "tableTo": "app", - "columnsFrom": [ - "app_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["app_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1404,9 +1265,7 @@ "indexes": { "invite_token_unique": { "name": "invite_token_unique", - "columns": [ - "token" - ], + "columns": ["token"], "isUnique": true } }, @@ -1415,12 +1274,8 @@ "name": "invite_creator_id_user_id_fk", "tableFrom": "invite", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1488,12 +1343,8 @@ "name": "item_layout_item_id_item_id_fk", "tableFrom": "item_layout", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1501,12 +1352,8 @@ "name": "item_layout_section_id_section_id_fk", "tableFrom": "item_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1514,23 +1361,15 @@ "name": "item_layout_layout_id_layout_id_fk", "tableFrom": "item_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "item_layout_item_id_section_id_layout_id_pk": { - "columns": [ - "item_id", - "section_id", - "layout_id" - ], + "columns": ["item_id", "section_id", "layout_id"], "name": "item_layout_item_id_section_id_layout_id_pk" } }, @@ -1584,12 +1423,8 @@ "name": "item_board_id_board_id_fk", "tableFrom": "item", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1644,12 +1479,8 @@ "name": "layout_board_id_board_id_fk", "tableFrom": "layout", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1718,12 +1549,8 @@ "name": "media_creator_id_user_id_fk", "tableFrom": "media", "tableTo": "user", - "columnsFrom": [ - "creator_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -1827,9 +1654,7 @@ "indexes": { "search_engine_short_unique": { "name": "search_engine_short_unique", - "columns": [ - "short" - ], + "columns": ["short"], "isUnique": true } }, @@ -1838,12 +1663,8 @@ "name": "search_engine_integration_id_integration_id_fk", "tableFrom": "search_engine", "tableTo": "integration", - "columnsFrom": [ - "integration_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["integration_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -1884,12 +1705,8 @@ "name": "section_collapse_state_user_id_user_id_fk", "tableFrom": "section_collapse_state", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1897,22 +1714,15 @@ "name": "section_collapse_state_section_id_section_id_fk", "tableFrom": "section_collapse_state", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "section_collapse_state_user_id_section_id_pk": { - "columns": [ - "user_id", - "section_id" - ], + "columns": ["user_id", "section_id"], "name": "section_collapse_state_user_id_section_id_pk" } }, @@ -1978,12 +1788,8 @@ "name": "section_layout_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -1991,12 +1797,8 @@ "name": "section_layout_layout_id_layout_id_fk", "tableFrom": "section_layout", "tableTo": "layout", - "columnsFrom": [ - "layout_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" }, @@ -2004,22 +1806,15 @@ "name": "section_layout_parent_section_id_section_id_fk", "tableFrom": "section_layout", "tableTo": "section", - "columnsFrom": [ - "parent_section_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "section_layout_section_id_layout_id_pk": { - "columns": [ - "section_id", - "layout_id" - ], + "columns": ["section_id", "layout_id"], "name": "section_layout_section_id_layout_id_pk" } }, @@ -2086,12 +1881,8 @@ "name": "section_board_id_board_id_fk", "tableFrom": "section", "tableTo": "board", - "columnsFrom": [ - "board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["board_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2122,9 +1913,7 @@ "indexes": { "serverSetting_settingKey_unique": { "name": "serverSetting_settingKey_unique", - "columns": [ - "setting_key" - ], + "columns": ["setting_key"], "isUnique": true } }, @@ -2161,9 +1950,7 @@ "indexes": { "user_id_idx": { "name": "user_id_idx", - "columns": [ - "user_id" - ], + "columns": ["user_id"], "isUnique": false } }, @@ -2172,12 +1959,8 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["user_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } @@ -2215,10 +1998,7 @@ "foreignKeys": {}, "compositePrimaryKeys": { "trusted_certificate_hostname_hostname_thumbprint_pk": { - "columns": [ - "hostname", - "thumbprint" - ], + "columns": ["hostname", "thumbprint"], "name": "trusted_certificate_hostname_hostname_thumbprint_pk" } }, @@ -2362,12 +2142,8 @@ "name": "user_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2375,12 +2151,8 @@ "name": "user_mobile_home_board_id_board_id_fk", "tableFrom": "user", "tableTo": "board", - "columnsFrom": [ - "mobile_home_board_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["mobile_home_board_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" }, @@ -2388,12 +2160,8 @@ "name": "user_default_search_engine_id_search_engine_id_fk", "tableFrom": "user", "tableTo": "search_engine", - "columnsFrom": [ - "default_search_engine_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["default_search_engine_id"], + "columnsTo": ["id"], "onDelete": "set null", "onUpdate": "no action" } @@ -2431,10 +2199,7 @@ "foreignKeys": {}, "compositePrimaryKeys": { "verificationToken_identifier_token_pk": { - "columns": [ - "identifier", - "token" - ], + "columns": ["identifier", "token"], "name": "verificationToken_identifier_token_pk" } }, @@ -2479,22 +2244,15 @@ "name": "widget_secret_item_id_item_id_fk", "tableFrom": "widget_secret", "tableTo": "item", - "columnsFrom": [ - "item_id" - ], - "columnsTo": [ - "id" - ], + "columnsFrom": ["item_id"], + "columnsTo": ["id"], "onDelete": "cascade", "onUpdate": "no action" } }, "compositePrimaryKeys": { "widget_secret_item_id_kind_pk": { - "columns": [ - "item_id", - "kind" - ], + "columns": ["item_id", "kind"], "name": "widget_secret_item_id_kind_pk" } }, diff --git a/packages/db/migrations/sqlite/meta/0045_snapshot.json b/packages/db/migrations/sqlite/meta/0045_snapshot.json new file mode 100644 index 000000000..fb6696542 --- /dev/null +++ b/packages/db/migrations/sqlite/meta/0045_snapshot.json @@ -0,0 +1,2699 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "5114a19e-3b78-482a-a68b-69874a05ee76", + "prevId": "ba1d8f76-d167-405c-97a6-ade428e51df1", + "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 + }, + "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 + }, + "ping_url": { + "name": "ping_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "assistant_configuration": { + "name": "assistant_configuration", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false, + "default": "'default'" + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "web_search_enabled": { + "name": "web_search_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'openrouter'" + }, + "base_url": { + "name": "base_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'https://openrouter.ai/api/v1'" + }, + "model_discovery_path": { + "name": "model_discovery_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'/models'" + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "encrypted_headers": { + "name": "encrypted_headers", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "assistant_message": { + "name": "assistant_message", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "format": { + "name": "format", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'ai-sdk/v6'" + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + } + }, + "indexes": { + "assistant_message__thread_id_created_at_idx": { + "name": "assistant_message__thread_id_created_at_idx", + "columns": ["thread_id", "created_at"], + "isUnique": false + } + }, + "foreignKeys": { + "assistant_message_thread_id_assistant_thread_id_fk": { + "name": "assistant_message_thread_id_assistant_thread_id_fk", + "tableFrom": "assistant_message", + "tableTo": "assistant_thread", + "columnsFrom": ["thread_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "assistant_thread": { + "name": "assistant_thread", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "model_id": { + "name": "model_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + } + }, + "indexes": { + "assistant_thread__user_id_updated_at_idx": { + "name": "assistant_thread__user_id_updated_at_idx", + "columns": ["user_id", "updated_at"], + "isUnique": false + } + }, + "foreignKeys": { + "assistant_thread_user_id_user_id_fk": { + "name": "assistant_thread_user_id_user_id_fk", + "tableFrom": "assistant_thread", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "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 + }, + "icon_color": { + "name": "icon_color", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "item_radius": { + "name": "item_radius", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'lg'" + }, + "disable_status": { + "name": "disable_status", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "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": {} + }, + "cron_job_configuration": { + "name": "cron_job_configuration", + "columns": { + "name": { + "name": "name", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_enabled": { + "name": "is_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "custom_widget_v2_definition": { + "name": "custom_widget_v2_definition", + "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": false, + "autoincrement": false + }, + "sources": { + "name": "sources", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "requests": { + "name": "requests", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "template": { + "name": "template", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "updated_at": { + "name": "updated_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": { + "custom_widget_v2_definition_creator_id_user_id_fk": { + "name": "custom_widget_v2_definition_creator_id_user_id_fk", + "tableFrom": "custom_widget_v2_definition", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "custom_widget_v2_secret": { + "name": "custom_widget_v2_secret", + "columns": { + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "encrypted_value": { + "name": "encrypted_value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "definition_id": { + "name": "definition_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "custom_widget_v2_secret_definition_id_fk": { + "name": "custom_widget_v2_secret_definition_id_fk", + "tableFrom": "custom_widget_v2_secret", + "tableTo": "custom_widget_v2_definition", + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "custom_widget_v2_secret_definition_id_source_id_kind_pk": { + "columns": ["definition_id", "source_id", "kind"], + "name": "custom_widget_v2_secret_definition_id_source_id_kind_pk" + } + }, + "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 + }, + "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 + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": true, + "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" + }, + "group_home_board_id_board_id_fk": { + "name": "group_home_board_id_board_id_fk", + "tableFrom": "group", + "tableTo": "board", + "columnsFrom": ["home_board_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "group_mobile_home_board_id_board_id_fk": { + "name": "group_mobile_home_board_id_board_id_fk", + "tableFrom": "group", + "tableTo": "board", + "columnsFrom": ["mobile_home_board_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 + }, + "app_id": { + "name": "app_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "integration__kind_idx": { + "name": "integration__kind_idx", + "columns": ["kind"], + "isUnique": false + } + }, + "foreignKeys": { + "integration_app_id_app_id_fk": { + "name": "integration_app_id_app_id_fk", + "tableFrom": "integration", + "tableTo": "app", + "columnsFrom": ["app_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "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_layout": { + "name": "item_layout", + "columns": { + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "layout_id": { + "name": "layout_id", + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "item_layout_item_id_item_id_fk": { + "name": "item_layout_item_id_item_id_fk", + "tableFrom": "item_layout", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "item_layout_section_id_section_id_fk": { + "name": "item_layout_section_id_section_id_fk", + "tableFrom": "item_layout", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "item_layout_layout_id_layout_id_fk": { + "name": "item_layout_layout_id_layout_id_fk", + "tableFrom": "item_layout", + "tableTo": "layout", + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "item_layout_item_id_section_id_layout_id_pk": { + "columns": ["item_id", "section_id", "layout_id"], + "name": "item_layout_item_id_section_id_layout_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "item": { + "name": "item", + "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 + }, + "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_board_id_board_id_fk": { + "name": "item_board_id_board_id_fk", + "tableFrom": "item", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "layout": { + "name": "layout", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "board_id": { + "name": "board_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "column_count": { + "name": "column_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "left_gutter_column_count": { + "name": "left_gutter_column_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "right_gutter_column_count": { + "name": "right_gutter_column_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "breakpoint": { + "name": "breakpoint", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'custom'" + } + }, + "indexes": {}, + "foreignKeys": { + "layout_board_id_board_id_fk": { + "name": "layout_board_id_board_id_fk", + "tableFrom": "layout", + "tableTo": "board", + "columnsFrom": ["board_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "custom_widget_definition": { + "name": "custom_widget_definition", + "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": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'none'" + }, + "header_name": { + "name": "header_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'GET'" + }, + "request_body": { + "name": "request_body", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_type": { + "name": "display_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'singleValue'" + }, + "display_config": { + "name": "display_config", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{\"json\": {}}'" + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(unixepoch())" + }, + "updated_at": { + "name": "updated_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": { + "custom_widget_definition_creator_id_user_id_fk": { + "name": "custom_widget_definition_creator_id_user_id_fk", + "tableFrom": "custom_widget_definition", + "tableTo": "user", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "custom_widget_secret": { + "name": "custom_widget_secret", + "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 + }, + "definition_id": { + "name": "definition_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "custom_widget_secret_definition_id_custom_widget_definition_id_fk": { + "name": "custom_widget_secret_definition_id_custom_widget_definition_id_fk", + "tableFrom": "custom_widget_secret", + "tableTo": "custom_widget_definition", + "columnsFrom": ["definition_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "custom_widget_secret_definition_id_kind_pk": { + "columns": ["definition_id", "kind"], + "name": "custom_widget_secret_definition_id_kind_pk" + } + }, + "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_collapse_state": { + "name": "section_collapse_state", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "section_id": { + "name": "section_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "collapsed": { + "name": "collapsed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "section_collapse_state_user_id_user_id_fk": { + "name": "section_collapse_state_user_id_user_id_fk", + "tableFrom": "section_collapse_state", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_collapse_state_section_id_section_id_fk": { + "name": "section_collapse_state_section_id_section_id_fk", + "tableFrom": "section_collapse_state", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_collapse_state_user_id_section_id_pk": { + "columns": ["user_id", "section_id"], + "name": "section_collapse_state_user_id_section_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "section_layout": { + "name": "section_layout", + "columns": { + "section_id": { + "name": "section_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "layout_id": { + "name": "layout_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "parent_section_id": { + "name": "parent_section_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "section_layout_section_id_section_id_fk": { + "name": "section_layout_section_id_section_id_fk", + "tableFrom": "section_layout", + "tableTo": "section", + "columnsFrom": ["section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_layout_layout_id_layout_id_fk": { + "name": "section_layout_layout_id_layout_id_fk", + "tableFrom": "section_layout", + "tableTo": "layout", + "columnsFrom": ["layout_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "section_layout_parent_section_id_section_id_fk": { + "name": "section_layout_parent_section_id_section_id_fk", + "tableFrom": "section_layout", + "tableTo": "section", + "columnsFrom": ["parent_section_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "section_layout_section_id_layout_id_pk": { + "columns": ["section_id", "layout_id"], + "name": "section_layout_section_id_layout_id_pk" + } + }, + "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": false, + "autoincrement": false + }, + "y_offset": { + "name": "y_offset", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'{\"json\": {}}'" + } + }, + "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" + } + }, + "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": {} + }, + "trusted_certificate_hostname": { + "name": "trusted_certificate_hostname", + "columns": { + "hostname": { + "name": "hostname", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "thumbprint": { + "name": "thumbprint", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "certificate": { + "name": "certificate", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "trusted_certificate_hostname_hostname_thumbprint_pk": { + "columns": ["hostname", "thumbprint"], + "name": "trusted_certificate_hostname_hostname_thumbprint_pk" + } + }, + "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 + }, + "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 + }, + "open_search_in_new_tab": { + "name": "open_search_in_new_tab", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "ddg_bangs": { + "name": "ddg_bangs", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "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 + }, + "enable_right_click_on_widgets": { + "name": "enable_right_click_on_widgets", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "completed_manage_tour": { + "name": "completed_manage_tour", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "completed_board_tour": { + "name": "completed_board_tour", + "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": {} + }, + "widget_secret": { + "name": "widget_secret", + "columns": { + "item_id": { + "name": "item_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "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 + } + }, + "indexes": {}, + "foreignKeys": { + "widget_secret_item_id_item_id_fk": { + "name": "widget_secret_item_id_item_id_fk", + "tableFrom": "widget_secret", + "tableTo": "item", + "columnsFrom": ["item_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "widget_secret_item_id_kind_pk": { + "columns": ["item_id", "kind"], + "name": "widget_secret_item_id_kind_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/packages/db/schema/postgresql.ts b/packages/db/schema/postgresql.ts index 03fcd7492..12aa9e5d1 100644 --- a/packages/db/schema/postgresql.ts +++ b/packages/db/schema/postgresql.ts @@ -536,7 +536,7 @@ export const assistantMessages = pgTable( .references(() => assistantThreads.id, { onDelete: "cascade" }), parentId: varchar({ length: 128 }), format: varchar({ length: 64 }).notNull().default("ai-sdk/v6"), - content: text().default(emptySuperJSON).notNull(), + content: text().notNull(), createdAt: timestamp().notNull().defaultNow(), }, (message) => ({ diff --git a/packages/db/schema/sqlite.ts b/packages/db/schema/sqlite.ts index f077ae6b0..9157a1335 100644 --- a/packages/db/schema/sqlite.ts +++ b/packages/db/schema/sqlite.ts @@ -527,7 +527,7 @@ export const assistantMessages = sqliteTable( .references(() => assistantThreads.id, { onDelete: "cascade" }), parentId: text(), format: text().notNull().default("ai-sdk/v6"), - content: text().default(emptySuperJSON).notNull(), + content: text().notNull(), createdAt: int({ mode: "timestamp" }) .notNull() .default(sql`(unixepoch())`), diff --git a/packages/integrations/src/plex/plex-integration.ts b/packages/integrations/src/plex/plex-integration.ts index 6b772a589..cd4e9d6e9 100644 --- a/packages/integrations/src/plex/plex-integration.ts +++ b/packages/integrations/src/plex/plex-integration.ts @@ -97,8 +97,8 @@ export class PlexIntegration extends Integration implements IMediaServerIntegrat const isAudioDirect = isStreamDirect(transcodeElement?.$.audioDecision); const containerChanged = Boolean( transcodeElement?.$.container && - mediaInfoElement?.$.container && - transcodeElement.$.container !== mediaInfoElement.$.container, + mediaInfoElement?.$.container && + transcodeElement.$.container !== mediaInfoElement.$.container, ); const bitrateKbps = parseOptionalNumber(sessionElement?.$.bandwidth) ?? parseOptionalNumber(mediaInfoElement?.$.bitrate); diff --git a/packages/translation/src/lang/ca.json b/packages/translation/src/lang/ca.json index 191706c23..f9f68b4c4 100644 --- a/packages/translation/src/lang/ca.json +++ b/packages/translation/src/lang/ca.json @@ -688,211 +688,6 @@ "add": "" } }, - "customWidget": { - "page": { - "list": { - "title": "", - "noResults": "", - "loading": "" - }, - "create": { - "title": "", - "subtitle": "" - }, - "edit": { - "title": "" - } - }, - "action": { - "create": "", - "import": "", - "save": "", - "delete": "", - "deleteConfirm": "", - "export": "", - "addMapping": "", - "addColumn": "", - "edit": "", - "removeMapping": "", - "removeColumn": "", - "addItem": "", - "removeItem": "", - "addBar": "", - "duplicate": "", - "copyAiPrompt": "", - "enable": "", - "disable": "", - "menu": "" - }, - "field": { - "name": "", - "description": "", - "iconUrl": "", - "url": "", - "authType": "", - "headerName": "", - "method": "", - "requestBody": "", - "displayType": "", - "jsonPath": "", - "jsonPathHint": "", - "label": "", - "unit": "", - "mappings": "", - "tablePath": "", - "tablePathHint": "", - "columns": "", - "header": "", - "items": "", - "gridColumns": "", - "cardStyle": "", - "bars": "", - "valuePath": "", - "maxPath": "", - "showPercentage": "", - "barSize": "", - "goodValues": "", - "dotSize": "", - "valueSize": "", - "labelPosition": "", - "kvLayout": "", - "striped": "", - "compact": "", - "maxHeight": "", - "color": "", - "buttonLabel": "", - "buttonColor": "", - "confirmText": "", - "confirmTextHint": "", - "successMessage": "", - "successMessageHint": "", - "enabled": "", - "template": { - "label": "", - "description": "" - } - }, - "placeholder": { - "exampleLabel": "", - "exampleLabelShort": "", - "exampleHeader": "", - "exampleUnit": "", - "iconUrl": "", - "url": "", - "headerName": "", - "jsonPath": "", - "tablePath": "", - "columnJsonPath": "", - "valuePath": "", - "maxPath": "", - "goodValues": "", - "color": "" - }, - "cardStyleOption": { - "filled": "", - "outline": "", - "subtle": "" - }, - "layoutOption": { - "list": "", - "grid": "" - }, - "sizeOption": { - "sm": "", - "md": "", - "lg": "", - "xl": "" - }, - "labelPositionOption": { - "above": "", - "below": "" - }, - "fieldset": { - "general": "", - "connection": "", - "display": "" - }, - "displayTypeDescription": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "method": { - "GET": "", - "POST": "", - "PUT": "", - "DELETE": "", - "PATCH": "" - }, - "authType": { - "none": "", - "bearer": "", - "basic": "", - "apiKeyHeader": "", - "apiKeyQuery": "" - }, - "displayType": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "secret": { - "apiKey": "", - "username": "", - "password": "", - "savedPlaceholder": "" - }, - "preview": { - "title": "", - "test": "", - "hint": "", - "rawResponse": "" - }, - "notification": { - "created": "", - "updated": "", - "deleted": "", - "imported": "", - "aiPromptCopied": "", - "aiPromptDescription": "", - "aiPromptCopy": "", - "aiPromptNoResponse": "", - "aiPromptCopyError": "", - "createError": "", - "updateError": "", - "importError": "", - "exportError": "", - "duplicated": "", - "duplicateError": "", - "toggleError": "", - "deleteError": "", - "previewError": "", - "executed": "", - "executeError": "" - }, - "table": { - "name": "", - "url": "", - "display": "" - }, - "widget": { - "disabled": "" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "", "description": "", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "Fonts RSS", "description": "Monitoritzeu i mostreu una o més fonts RSS, ATOM o JSON genèriques", @@ -3744,40 +3323,6 @@ "internalServerError": "" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "", "description": "", @@ -3901,26 +3446,6 @@ "unhealthy": "" } }, - "customApi": { - "name": "", - "description": "", - "option": { - "definitionId": { - "label": "" - }, - "refreshInterval": { - "label": "", - "description": "" - } - }, - "noDefinition": "", - "definitionNotFound": "", - "noDisplayOutput": "", - "executeConfirm": "", - "executing": "", - "executeSuccess": "", - "executeFailed": "" - }, "beszelSystemTable": { "name": "", "description": "", @@ -4171,6 +3696,256 @@ "subtitle": "" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Inici", "boards": "Taulers", "apps": "Aplicacions", "integrations": "Integracions", - "customWidgets": "", "searchEngies": "Motors de cerca", "medias": "Multimèdia", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Gestiona", "boards": { "label": "Taulers" @@ -5728,18 +5506,6 @@ "label": "Edita" } }, - "custom-widgets": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "", - "flow": { - "label": "" - } - } - }, "users": { "label": "Usuaris", "create": { diff --git a/packages/translation/src/lang/cs.json b/packages/translation/src/lang/cs.json index 8e9a14e72..1c7eeaa15 100644 --- a/packages/translation/src/lang/cs.json +++ b/packages/translation/src/lang/cs.json @@ -688,211 +688,6 @@ "add": "Přidat aplikaci" } }, - "customWidget": { - "page": { - "list": { - "title": "", - "noResults": "", - "loading": "Načítání..." - }, - "create": { - "title": "", - "subtitle": "" - }, - "edit": { - "title": "" - } - }, - "action": { - "create": "Vytvořit", - "import": "Import", - "save": "Uložit", - "delete": "", - "deleteConfirm": "", - "export": "Export", - "addMapping": "", - "addColumn": "", - "edit": "Upravit", - "removeMapping": "", - "removeColumn": "", - "addItem": "Přidat položku", - "removeItem": "Odebrat položku", - "addBar": "Přidat lištu", - "duplicate": "", - "copyAiPrompt": "", - "enable": "Povolit", - "disable": "Zakázat", - "menu": "Akce" - }, - "field": { - "name": "Název", - "description": "Popis", - "iconUrl": "URL ikony", - "url": "URL", - "authType": "Typ ověření", - "headerName": "", - "method": "Metoda", - "requestBody": "", - "displayType": "", - "jsonPath": "", - "jsonPathHint": "", - "label": "", - "unit": "", - "mappings": "", - "tablePath": "", - "tablePathHint": "", - "columns": "", - "header": "", - "items": "", - "gridColumns": "", - "cardStyle": "", - "bars": "", - "valuePath": "", - "maxPath": "", - "showPercentage": "", - "barSize": "", - "goodValues": "", - "dotSize": "", - "valueSize": "", - "labelPosition": "", - "kvLayout": "", - "striped": "", - "compact": "", - "maxHeight": "", - "color": "", - "buttonLabel": "", - "buttonColor": "", - "confirmText": "", - "confirmTextHint": "", - "successMessage": "", - "successMessageHint": "", - "enabled": "", - "template": { - "label": "", - "description": "" - } - }, - "placeholder": { - "exampleLabel": "Teplota CPU", - "exampleLabelShort": "Teplota CPU", - "exampleHeader": "Název", - "exampleUnit": "°C", - "iconUrl": "https://...", - "url": "https://api.example.com/api/v1/status", - "headerName": "X-API klíč", - "jsonPath": "$.data.value", - "tablePath": "$.data.items", - "columnJsonPath": "$.jméno", - "valuePath": "$.data.used", - "maxPath": "$.data.total", - "goodValues": "", - "color": "" - }, - "cardStyleOption": { - "filled": "", - "outline": "", - "subtle": "" - }, - "layoutOption": { - "list": "", - "grid": "" - }, - "sizeOption": { - "sm": "Malé", - "md": "Střední", - "lg": "Velké", - "xl": "Extra velké" - }, - "labelPositionOption": { - "above": "Nad", - "below": "Pod" - }, - "fieldset": { - "general": "Obecné", - "connection": "API propojení", - "display": "" - }, - "displayTypeDescription": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "method": { - "GET": "GET", - "POST": "POST", - "PUT": "PUT", - "DELETE": "", - "PATCH": "" - }, - "authType": { - "none": "", - "bearer": "", - "basic": "", - "apiKeyHeader": "Klíč API (záhlaví)", - "apiKeyQuery": "Klíč API (dotazy)" - }, - "displayType": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "secret": { - "apiKey": "", - "username": "Uživatelské jméno", - "password": "Heslo", - "savedPlaceholder": "••••••• (uloženo, ponechte prázdné pro zachování)" - }, - "preview": { - "title": "Náhled", - "test": "Test", - "hint": "", - "rawResponse": "" - }, - "notification": { - "created": "", - "updated": "", - "deleted": "", - "imported": "", - "aiPromptCopied": "", - "aiPromptDescription": "", - "aiPromptCopy": "", - "aiPromptNoResponse": "", - "aiPromptCopyError": "", - "createError": "", - "updateError": "", - "importError": "", - "exportError": "", - "duplicated": "", - "duplicateError": "", - "toggleError": "", - "deleteError": "", - "previewError": "", - "executed": "", - "executeError": "" - }, - "table": { - "name": "", - "url": "URL", - "display": "" - }, - "widget": { - "disabled": "" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "", "description": "", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "", "description": "", @@ -3744,40 +3323,6 @@ "internalServerError": "" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "", "description": "", @@ -3901,26 +3446,6 @@ "unhealthy": "" } }, - "customApi": { - "name": "", - "description": "", - "option": { - "definitionId": { - "label": "" - }, - "refreshInterval": { - "label": "", - "description": "" - } - }, - "noDefinition": "", - "definitionNotFound": "", - "noDisplayOutput": "", - "executeConfirm": "", - "executing": "", - "executeSuccess": "", - "executeFailed": "" - }, "beszelSystemTable": { "name": "Systémy Beszel (tabulka)", "description": "Tabulkový přehled všech monitorovaných systémů Beszel s řaditelnými sloupci a indikátory stavu", @@ -4171,6 +3696,256 @@ "subtitle": "" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Domovská stránka", "boards": "Plochy", "apps": "Aplikace", "integrations": "", - "customWidgets": "", "searchEngies": "", "medias": "", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Spravovat", "boards": { "label": "Plochy" @@ -5728,18 +5506,6 @@ "label": "Upravit" } }, - "custom-widgets": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "", - "flow": { - "label": "" - } - } - }, "users": { "label": "Uživatelé", "create": { diff --git a/packages/translation/src/lang/el.json b/packages/translation/src/lang/el.json index 89b71379e..61c62b090 100644 --- a/packages/translation/src/lang/el.json +++ b/packages/translation/src/lang/el.json @@ -688,211 +688,6 @@ "add": "" } }, - "customWidget": { - "page": { - "list": { - "title": "Προσαρμοσμένα Widgets", - "noResults": "Δεν υπάρχουν ακόμα προσαρμοσμένα widgets. Δημιουργήστε το πρώτο σας!", - "loading": "Φόρτωση..." - }, - "create": { - "title": "Δημιουργία Προσαρμοσμένου Widget", - "subtitle": "Ορίστε μια διεύθυνση URL API, πιστοποίηση και τον τρόπο εμφάνισης των δεδομένων απόκρισης." - }, - "edit": { - "title": "Επεξεργασία Προσαρμοσμένου Widget" - } - }, - "action": { - "create": "Δημιουργία", - "import": "Εισαγωγή", - "save": "Αποθήκευση", - "delete": "Διαγραφή Προσαρμοσμένου Widget", - "deleteConfirm": "Είστε βέβαιοι ότι θέλετε να διαγράψετε το \"{name}\"; Αυτή η ενέργεια δεν μπορεί να αναιρεθεί.", - "export": "Εξαγωγή", - "addMapping": "Προσθήκη Αντιστοίχισης", - "addColumn": "Προσθήκη Στήλης", - "edit": "Επεξεργασία", - "removeMapping": "Αφαίρεση αντιστοίχισης", - "removeColumn": "Αφαίρεση στήλης", - "addItem": "Προσθήκη Στοιχείου", - "removeItem": "Αφαίρεση στοιχείου", - "addBar": "Προσθήκη Μπάρας", - "duplicate": "Αντιγραφή", - "copyAiPrompt": "Αντιγραφή προτροπής AI", - "enable": "Ενεργοποίηση", - "disable": "Απενεργοποίηση", - "menu": "Ενέργειες" - }, - "field": { - "name": "Όνομα", - "description": "Περιγραφή", - "iconUrl": "URL Εικονιδίου", - "url": "URL", - "authType": "Τύπος Πιστοποίησης", - "headerName": "Όνομα Παραμέτρου Κεφαλίδας/Ερωτήματος", - "method": "Μέθοδος", - "requestBody": "Σώμα Αιτήματος", - "displayType": "Τύπος Εμφάνισης", - "jsonPath": "Διαδρομή JSON", - "jsonPathHint": "Χρησιμοποιήστε σύνταξη JSONPath για εξαγωγή τιμών, π.χ. $.data.temperature ή $.items[0].name", - "label": "Ετικέτα", - "unit": "Μονάδα", - "mappings": "Αντιστοιχίσεις", - "tablePath": "Διαδρομή JSON Πίνακα", - "tablePathHint": "Διαδρομή προς τον πίνακα στην απόκριση, π.χ. $.data.items", - "columns": "Στήλες", - "header": "Κεφαλίδα", - "items": "Στοιχεία", - "gridColumns": "Στήλες Πλέγματος", - "cardStyle": "Στυλ Κάρτας", - "bars": "Μπάρες", - "valuePath": "Διαδρομή JSON Τιμής", - "maxPath": "Διαδρομή JSON Μέγιστης Τιμής", - "showPercentage": "Εμφάνιση Ποσοστού", - "barSize": "Μέγεθος Μπάρας", - "goodValues": "Καλές Τιμές (διαχωρισμένες με κόμμα)", - "dotSize": "Μέγεθος Κουκκίδας", - "valueSize": "Μέγεθος Τιμής", - "labelPosition": "Θέση Ετικέτας", - "kvLayout": "Διάταξη", - "striped": "Ριγωτές Γραμμές", - "compact": "Συμπαγής Λειτουργία", - "maxHeight": "Μέγιστο Ύψος (px)", - "color": "Χρώμα", - "buttonLabel": "", - "buttonColor": "", - "confirmText": "", - "confirmTextHint": "", - "successMessage": "", - "successMessageHint": "", - "enabled": "", - "template": { - "label": "", - "description": "" - } - }, - "placeholder": { - "exampleLabel": "", - "exampleLabelShort": "", - "exampleHeader": "", - "exampleUnit": "", - "iconUrl": "", - "url": "", - "headerName": "", - "jsonPath": "", - "tablePath": "", - "columnJsonPath": "", - "valuePath": "", - "maxPath": "", - "goodValues": "", - "color": "" - }, - "cardStyleOption": { - "filled": "", - "outline": "", - "subtle": "" - }, - "layoutOption": { - "list": "", - "grid": "" - }, - "sizeOption": { - "sm": "", - "md": "", - "lg": "", - "xl": "" - }, - "labelPositionOption": { - "above": "", - "below": "" - }, - "fieldset": { - "general": "", - "connection": "", - "display": "" - }, - "displayTypeDescription": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "method": { - "GET": "", - "POST": "", - "PUT": "", - "DELETE": "", - "PATCH": "" - }, - "authType": { - "none": "", - "bearer": "", - "basic": "", - "apiKeyHeader": "", - "apiKeyQuery": "" - }, - "displayType": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "secret": { - "apiKey": "", - "username": "", - "password": "", - "savedPlaceholder": "" - }, - "preview": { - "title": "", - "test": "", - "hint": "", - "rawResponse": "" - }, - "notification": { - "created": "", - "updated": "", - "deleted": "", - "imported": "", - "aiPromptCopied": "", - "aiPromptDescription": "", - "aiPromptCopy": "", - "aiPromptNoResponse": "", - "aiPromptCopyError": "", - "createError": "", - "updateError": "", - "importError": "", - "exportError": "", - "duplicated": "", - "duplicateError": "", - "toggleError": "", - "deleteError": "", - "previewError": "", - "executed": "", - "executeError": "" - }, - "table": { - "name": "", - "url": "", - "display": "" - }, - "widget": { - "disabled": "" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "Αποτυχία λήψης δεδομένων Paperless-ngx" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "", "description": "", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "", "description": "", @@ -3744,40 +3323,6 @@ "internalServerError": "Αποτυχία λήψης δεδομένων διαθεσιμότητας" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "Στατιστικά Ήχου", "description": "Στατιστικά βιβλιοθήκης και αναπαραγωγής από Navidrome ή Audiobookshelf", @@ -3901,26 +3446,6 @@ "unhealthy": "" } }, - "customApi": { - "name": "", - "description": "", - "option": { - "definitionId": { - "label": "" - }, - "refreshInterval": { - "label": "", - "description": "" - } - }, - "noDefinition": "", - "definitionNotFound": "", - "noDisplayOutput": "", - "executeConfirm": "", - "executing": "", - "executeSuccess": "", - "executeFailed": "" - }, "beszelSystemTable": { "name": "Beszel Συστήματα (Πίνακας)", "description": "Προβολή πίνακα όλων των συστημάτων που παρακολουθούνται από το Beszel με ταξινομήσιμες στήλες και δείκτες κατάστασης", @@ -4171,6 +3696,256 @@ "subtitle": "Κίνηση δικτύου των docker containers" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Αρχική", "boards": "Πίνακες", "apps": "Εφαρμογές", "integrations": "", - "customWidgets": "", "searchEngies": "", "medias": "", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Διαχείριση", "boards": { "label": "Πίνακες" @@ -5728,18 +5506,6 @@ "label": "Επεξεργασία" } }, - "custom-widgets": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "", - "flow": { - "label": "" - } - } - }, "users": { "label": "Χρήστες", "create": { diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index d9b37c5ad..403edc284 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -2680,6 +2680,12 @@ "noProjectSelected": "No project selected", "runnerStatus": "Runner: {status}", "updatedAt": "Updated {date}", + "projectId": "Project: {id}", + "sessionReceived": "Session received: {value}", + "sessionSent": "Session sent: {value}", + "sessionId": "Session: {id}", + "startedAt": "Started {date}", + "emptyItems": "No active or recent jobs in this snapshot", "metric": { "running": "Running", "completed": "Done", @@ -3082,6 +3088,7 @@ }, "advanced": { "entityId": "Entity ID: {id}", + "lastChanged": "Changed {date}", "lastUpdated": "Updated {date}", "attribute": { "unit": "Unit", @@ -3110,7 +3117,9 @@ }, "advanced": { "lastExecuted": "Last run at {time}", - "automationId": "Automation ID: {id}" + "automationId": "Automation ID: {id}", + "ready": "Ready to run", + "noPermission": "No permission to run this automation" }, "status": { "running": "Running automation", @@ -3123,6 +3132,14 @@ "stockPrice": { "name": "Stock Price", "description": "Displays the current stock price of a company", + "advanced": { + "currentPrice": "Current price", + "previousClose": "Previous close", + "change": "Change", + "changePercentage": "Change (%)", + "minimum": "Minimum", + "maximum": "Maximum" + }, "option": { "stock": { "label": "Stock symbol" @@ -3311,6 +3328,11 @@ }, "title": "Indexer manager", "testAll": "Test all", + "status": { + "healthy": "Healthy", + "unhealthy": "Unhealthy", + "disabled": "Disabled" + }, "error": { "internalServerError": "Failed to fetch indexers status" } @@ -3368,7 +3390,10 @@ "minutes": "{count} minutes", "used": "Used", "available": "Available", - "lastSeen": "Last status update: {lastSeen}" + "lastSeen": "Last status update: {lastSeen}", + "updatesAvailable": "{count, plural, one {# update available} other {# updates available}}", + "rebootRequired": "Reboot required", + "rebootNotRequired": "No reboot required" }, "memory": {}, "error": { @@ -3487,7 +3512,13 @@ }, "server": { "buildServer": "Build", - "resourceCounts": "{applications, plural, one {# app} other {# apps}} / {services, plural, one {# service} other {# services}}" + "resourceCounts": "{applications, plural, one {# app} other {# apps}} / {services, plural, one {# service} other {# services}}", + "reachability": "Reachability", + "usability": "Usability" + }, + "source": { + "url": "Source: {url}", + "unavailable": "{source}: unavailable" }, "instances": { "title": "Instances" @@ -3506,7 +3537,11 @@ "restarting": "Restarting", "unknown": "Unknown", "online": "Online", - "offline": "Offline" + "offline": "Offline", + "reachable": "Reachable", + "unreachable": "Unreachable", + "usable": "Usable", + "unusable": "Unusable" } }, "vpn": { @@ -4042,6 +4077,9 @@ "movies": "Missing Movies", "providers": "Provider Issues", "status": "Health Issues", + "sonarrSignalr": "Sonarr SignalR", + "radarrSignalr": "Radarr SignalR", + "announcements": "Announcements", "option": { "showMissingEpisodes": { "label": "Show missing episodes", @@ -4640,6 +4678,16 @@ }, "networkControllerSummary": { "option": {}, + "advanced": { + "updated": "Updated", + "metric": { + "latency": "Latency", + "ping": "Ping", + "uptime": "Uptime", + "users": "Users", + "guests": "Guests" + } + }, "card": { "vpn": { "countConnected": "{count, plural, one {# connected} other {# connected}}", @@ -4658,6 +4706,9 @@ "description": "Displays the summary of a Network Controller (like UniFi Controller)" }, "networkControllerStatus": { + "advanced": { + "updatedAt": "Updated {date}" + }, "card": { "variants": { "wired": { @@ -4789,7 +4840,8 @@ "range": { "twelveHours": "12h", "oneDay": "24h", - "all": "All" + "all": "All", + "lastThirty": "Last 30" } }, "uptimeKuma": { @@ -5004,7 +5056,9 @@ } }, "status": { - "unhealthy": "Unhealthy" + "unhealthy": "Unhealthy", + "smart": "SMART", + "free": "{percentage}% free" } }, "customApi": { @@ -5125,6 +5179,12 @@ }, "column": { "system": "System", + "source": "Source", + "hostname": "Hostname", + "os": "OS", + "cpuModel": "CPU model", + "cores": "Cores", + "memoryTotal": "Memory total", "cpu": "CPU", "memory": "Memory", "disk": "Disk", @@ -5185,6 +5245,14 @@ "empty": { "noSystems": "No systems found" }, + "metadata": { + "hostname": "Hostname", + "os": "OS", + "cpuModel": "CPU model", + "cores": "Cores", + "memoryTotal": "Memory total", + "source": "Source" + }, "metric": { "cpu": "CPU", "memory": "Memory", diff --git a/packages/translation/src/lang/et.json b/packages/translation/src/lang/et.json index b490502e0..283e6da38 100644 --- a/packages/translation/src/lang/et.json +++ b/packages/translation/src/lang/et.json @@ -688,211 +688,6 @@ "add": "" } }, - "customWidget": { - "page": { - "list": { - "title": "", - "noResults": "", - "loading": "" - }, - "create": { - "title": "", - "subtitle": "" - }, - "edit": { - "title": "" - } - }, - "action": { - "create": "", - "import": "", - "save": "", - "delete": "", - "deleteConfirm": "", - "export": "", - "addMapping": "", - "addColumn": "", - "edit": "", - "removeMapping": "", - "removeColumn": "", - "addItem": "", - "removeItem": "", - "addBar": "", - "duplicate": "", - "copyAiPrompt": "", - "enable": "", - "disable": "", - "menu": "" - }, - "field": { - "name": "", - "description": "", - "iconUrl": "", - "url": "", - "authType": "", - "headerName": "", - "method": "", - "requestBody": "", - "displayType": "", - "jsonPath": "", - "jsonPathHint": "", - "label": "", - "unit": "", - "mappings": "", - "tablePath": "", - "tablePathHint": "", - "columns": "", - "header": "", - "items": "", - "gridColumns": "", - "cardStyle": "", - "bars": "", - "valuePath": "", - "maxPath": "", - "showPercentage": "", - "barSize": "", - "goodValues": "", - "dotSize": "", - "valueSize": "", - "labelPosition": "", - "kvLayout": "", - "striped": "", - "compact": "", - "maxHeight": "", - "color": "", - "buttonLabel": "", - "buttonColor": "", - "confirmText": "", - "confirmTextHint": "", - "successMessage": "", - "successMessageHint": "", - "enabled": "", - "template": { - "label": "", - "description": "" - } - }, - "placeholder": { - "exampleLabel": "", - "exampleLabelShort": "", - "exampleHeader": "", - "exampleUnit": "", - "iconUrl": "", - "url": "", - "headerName": "", - "jsonPath": "", - "tablePath": "", - "columnJsonPath": "", - "valuePath": "", - "maxPath": "", - "goodValues": "", - "color": "" - }, - "cardStyleOption": { - "filled": "", - "outline": "", - "subtle": "" - }, - "layoutOption": { - "list": "", - "grid": "" - }, - "sizeOption": { - "sm": "", - "md": "", - "lg": "", - "xl": "" - }, - "labelPositionOption": { - "above": "", - "below": "" - }, - "fieldset": { - "general": "", - "connection": "", - "display": "" - }, - "displayTypeDescription": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "method": { - "GET": "", - "POST": "", - "PUT": "", - "DELETE": "", - "PATCH": "" - }, - "authType": { - "none": "", - "bearer": "", - "basic": "", - "apiKeyHeader": "", - "apiKeyQuery": "" - }, - "displayType": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "secret": { - "apiKey": "", - "username": "", - "password": "", - "savedPlaceholder": "" - }, - "preview": { - "title": "", - "test": "", - "hint": "", - "rawResponse": "" - }, - "notification": { - "created": "", - "updated": "", - "deleted": "", - "imported": "", - "aiPromptCopied": "", - "aiPromptDescription": "", - "aiPromptCopy": "", - "aiPromptNoResponse": "", - "aiPromptCopyError": "", - "createError": "", - "updateError": "", - "importError": "", - "exportError": "", - "duplicated": "", - "duplicateError": "", - "toggleError": "", - "deleteError": "", - "previewError": "", - "executed": "", - "executeError": "" - }, - "table": { - "name": "", - "url": "", - "display": "" - }, - "widget": { - "disabled": "" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "", "description": "", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "RSS-voogud", "description": "Jälgi ja kuva üht või enamat üldist RSS-, ATOM- või JSON-voogu", @@ -3744,40 +3323,6 @@ "internalServerError": "" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "", "description": "", @@ -3901,26 +3446,6 @@ "unhealthy": "" } }, - "customApi": { - "name": "", - "description": "", - "option": { - "definitionId": { - "label": "" - }, - "refreshInterval": { - "label": "", - "description": "" - } - }, - "noDefinition": "", - "definitionNotFound": "", - "noDisplayOutput": "", - "executeConfirm": "", - "executing": "", - "executeSuccess": "", - "executeFailed": "" - }, "beszelSystemTable": { "name": "", "description": "", @@ -4171,6 +3696,256 @@ "subtitle": "" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Kodu", "boards": "Töölauad", "apps": "Rakendused", "integrations": "Integratsioonid", - "customWidgets": "", "searchEngies": "Otsingumootorid", "medias": "Meedia", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "", "boards": { "label": "" @@ -5728,18 +5506,6 @@ "label": "" } }, - "custom-widgets": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "", - "flow": { - "label": "" - } - } - }, "users": { "label": "", "create": { diff --git a/packages/translation/src/lang/fi.json b/packages/translation/src/lang/fi.json index 5db39e6f4..6c8fe0f95 100644 --- a/packages/translation/src/lang/fi.json +++ b/packages/translation/src/lang/fi.json @@ -688,211 +688,6 @@ "add": "Lisää sovellus" } }, - "customWidget": { - "page": { - "list": { - "title": "Mukautetut widgetit", - "noResults": "Ei vielä mukautettuja widgettejä. Luo ensimmäinen!", - "loading": "Ladataan..." - }, - "create": { - "title": "Luo mukautettu widget", - "subtitle": "Määritä API-URL, todennus ja miten vastaustiedot näytetään." - }, - "edit": { - "title": "Muokkaa mukautettua widgettiä" - } - }, - "action": { - "create": "Luo", - "import": "Tuo", - "save": "Tallenna", - "delete": "Poista mukautettu widget", - "deleteConfirm": "Haluatko varmasti poistaa \"{name}\"? Tätä toimintoa ei voi peruuttaa.", - "export": "Vie", - "addMapping": "Lisää kartoitus", - "addColumn": "Lisää sarake", - "edit": "Muokkaa", - "removeMapping": "Poista kartoitus", - "removeColumn": "Poista sarake", - "addItem": "Lisää kohde", - "removeItem": "Poista kohde", - "addBar": "Lisää palkki", - "duplicate": "Monista", - "copyAiPrompt": "Kopioi AI-kehoteprompt", - "enable": "Ota käyttöön", - "disable": "Poista käytöstä", - "menu": "Toiminnot" - }, - "field": { - "name": "Nimi", - "description": "Kuvaus", - "iconUrl": "Kuvakkeen URL-osoite", - "url": "URL", - "authType": "Tunnistautumistyyppi", - "headerName": "Otsikko/kyselyparametrin nimi", - "method": "Menetelmä", - "requestBody": "Pyynnön runko", - "displayType": "Näyttötyyppi", - "jsonPath": "JSON-polku", - "jsonPathHint": "Käytä JSONPath-syntaksia arvojen poimimiseen, esim. $.data.temperature tai $.items[0].name", - "label": "Tunniste", - "unit": "Yksikkö", - "mappings": "Kartoitukset", - "tablePath": "Taulukon JSON-polku", - "tablePathHint": "Polku vastauksen taulukkoon, esim. $.data.items", - "columns": "Sarakkeet", - "header": "Otsikko", - "items": "Kohteet", - "gridColumns": "Ruudukon sarakkeet", - "cardStyle": "Kortin tyyli", - "bars": "Palkit", - "valuePath": "Arvon JSON-polku", - "maxPath": "Maksimiarvon JSON-polku", - "showPercentage": "Näytä prosenttiosuus", - "barSize": "Palkin koko", - "goodValues": "Hyvät arvot (pilkuin eroteltuina)", - "dotSize": "Pisteen koko", - "valueSize": "Arvon koko", - "labelPosition": "Tunnisteen sijainti", - "kvLayout": "Asettelu", - "striped": "Raidalliset rivit", - "compact": "Tiivis tila", - "maxHeight": "Maksimikorkeus (px)", - "color": "Väri", - "buttonLabel": "Painikkeen teksti", - "buttonColor": "Painikkeen väri", - "confirmText": "Vahvistusteksti", - "confirmTextHint": "Jos asetettu, vahvistusvalintaikkuna tulee esiin ennen pyynnön suorittamista", - "successMessage": "Onnistumisviesti", - "successMessageHint": "Viesti, joka näytetään onnistuneen suorituksen jälkeen", - "enabled": "Käytössä", - "template": { - "label": "JSX-mallipohja", - "description": "Mantine JSX -mallipohja. Käytä vastauskenttiä datan sidonnoilla (esim. data.name). Käytä vain sallittuja komponentteja. Kielletyt: constructor, __proto__, eval, Function, window, document." - } - }, - "placeholder": { - "exampleLabel": "CPU-lämpötila", - "exampleLabelShort": "CPU-lämpö", - "exampleHeader": "Nimi", - "exampleUnit": "°C", - "iconUrl": "https://...", - "url": "https://api.example.com/api/v1/status", - "headerName": "X-API-Key", - "jsonPath": "$.data.value", - "tablePath": "$.data.items", - "columnJsonPath": "$.nimi", - "valuePath": "$.data.used", - "maxPath": "$.data.total", - "goodValues": "online, true, up", - "color": "sininen" - }, - "cardStyleOption": { - "filled": "Täytetty", - "outline": "Ääriviiva", - "subtle": "Hienovarainen" - }, - "layoutOption": { - "list": "Luettelo", - "grid": "Ruudukko" - }, - "sizeOption": { - "sm": "Pieni", - "md": "Keskikokoinen", - "lg": "Suuri", - "xl": "Erittäin suuri" - }, - "labelPositionOption": { - "above": "Yläpuolella", - "below": "Alapuolella" - }, - "fieldset": { - "general": "Yleiset", - "connection": "API-yhteys", - "display": "Näyttöasetukset" - }, - "displayTypeDescription": { - "singleValue": "Näytä yksi poimittu arvo tunnisteella ja yksiköllä", - "keyValue": "Näytä useita tunnisteellisia arvoja vierekkäin", - "table": "Näytä tietorivit taulukkomuodossa", - "statGrid": "Värilliset tilastokortit ruudukossa – kuten Pi-Hole- tai Speedtest-widgetit", - "progressBars": "Edistymispalkit, jotka näyttävät käyttöasteen tai valmistumisen – levylle, muistille, kiintiöille", - "statusIndicator": "Värilliset tilapisteet, jotka näyttävät online/offline- tai terveydentilan", - "countGrid": "Tiiviit numero + tunniste -laskurit tiukassa ruudukossa", - "raw": "Muotoiltu JSON-tuloste vianetsintään", - "actionButton": "Painike, joka laukaisee pyynnön napsautettaessa", - "customJsx": "Mukautettu JSX-asettelu käyttäen sallittuja Mantine-komponentteja täydellä API-tietojen sidonnalla" - }, - "method": { - "GET": "GET", - "POST": "POST", - "PUT": "PUT", - "DELETE": "DELETE", - "PATCH": "PATCH" - }, - "authType": { - "none": "Ei mitään", - "bearer": "Bearer-tunniste", - "basic": "Basic-todennus", - "apiKeyHeader": "API-avain (otsikko)", - "apiKeyQuery": "API-avain (kysely)" - }, - "displayType": { - "singleValue": "Yksittäinen arvo", - "keyValue": "Avain-arvo", - "table": "Taulukko", - "statGrid": "Tilastoruudukko", - "progressBars": "Edistymispalkit", - "statusIndicator": "Tilan ilmaisin", - "countGrid": "Laskuriruudukko", - "raw": "Raaka JSON", - "actionButton": "Toimintopainike", - "customJsx": "Mukautettu JSX" - }, - "secret": { - "apiKey": "API-avain / token", - "username": "Käyttäjätunnus", - "password": "Salasana", - "savedPlaceholder": "••••••• (tallennettu, jätä tyhjäksi säilyttääksesi)" - }, - "preview": { - "title": "Esikatselu", - "test": "Testaa", - "hint": "Napsauta Testaa nähdäksesi API-vastauksen nykyisillä asetuksillasi.", - "rawResponse": "Raaka JSON-vastaus" - }, - "notification": { - "created": "Widget \"{name}\" luotiin onnistuneesti.", - "updated": "Widget \"{name}\" päivitettiin onnistuneesti.", - "deleted": "Widget \"{name}\" poistettiin.", - "imported": "Widget tuotiin onnistuneesti.", - "aiPromptCopied": "AI-kehoteprompt kopioitu leikepöydälle", - "aiPromptDescription": "Kopioi valmis kehoteprompt liitettäväksi mihin tahansa AI-chatbottiin (ChatGPT, Claude, Gemini...). Se sisältää täyden widget-skeeman ja API-vastauksesi, jotta AI voi luoda sinulle tuotavissa olevan JSON-asetuksen.", - "aiPromptCopy": "Kopioi leikepöydälle", - "aiPromptNoResponse": "Vinkki: Suorita testi ensin sisällyttääksesi API-vastauksesi kehotepromptiin parempien tulosten saamiseksi.", - "aiPromptCopyError": "Kehotepromptin kopiointi leikepöydälle epäonnistui. Selaimesi ei ehkä tue tätä ominaisuutta.", - "createError": "Widgetin luonti epäonnistui. Tarkista, että API-päätepisteesi on tavoitettavissa.", - "updateError": "Widgetin päivitys epäonnistui. Muutoksiasi ei tallennettu.", - "importError": "Widgetin tuonti epäonnistui. Varmista, että tiedosto on kelvollinen mukautetun widgetin JSON-vienti.", - "exportError": "Widgetin vienti epäonnistui.", - "duplicated": "Widget \"{name}\" kopioitiin.", - "duplicateError": "Widgetin kopiointi epäonnistui.", - "toggleError": "Widgetin tilan vaihto epäonnistui.", - "deleteError": "Widgetin poisto epäonnistui.", - "previewError": "Esikatselun nouto epäonnistui. Tarkista URL ja yritä uudelleen.", - "executed": "Toiminto suoritettu onnistuneesti.", - "executeError": "Toiminto epäonnistui: {error}" - }, - "table": { - "name": "Nimi", - "url": "URL", - "display": "Näyttö" - }, - "widget": { - "disabled": "Tämä widget on poistettu käytöstä" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "Paperless-ngx-tietojen haku epäonnistui" } }, - "patchmon": { - "name": "PatchMon", - "description": "Yleiskatsaus isäntien päivitystilanteesta PatchMonista", - "title": "PatchMon-tilastot", - "totalHosts": "Isännät yhteensä", - "hostsNeedingUpdates": "Päivitystä tarvitsevat", - "securityUpdates": "Tietoturvapäivitykset", - "upToDateHosts": "Ajan tasalla olevat isännät", - "hostsWithSecurityUpdates": "Isännät, joilla on tietoturvapäivityksiä", - "recentUpdates24h": "Päivitykset (24 h)", - "totalOutdatedPackages": "Vanhentuneet paketit", - "totalRepos": "Pakettivarastot", - "osDistribution": "Käyttöjärjestelmien jakauma", - "compliance": "Päivityskattavuus", - "complianceRatio": "{upToDate} / {total}", - "lastUpdated": "Päivitetty {time}", - "option": { - "showTotalHosts": { - "label": "Näytä isännät yhteensä", - "description": "Näytä valvottujen isäntien kokonaismäärä" - }, - "showHostsNeedingUpdates": { - "label": "Näytä päivitystä tarvitsevat isännät", - "description": "Näytä isännät, joilla on vähintään yksi vanhentunut paketti" - }, - "showSecurityUpdates": { - "label": "Näytä tietoturvapäivitykset", - "description": "Näytä saatavilla olevien tietoturvapäivitysten kokonaismäärä" - }, - "showUpToDateHosts": { - "label": "Näytä ajan tasalla olevat isännät", - "description": "Näytä isännät, joissa ei ole vanhentuneita paketteja" - }, - "showHostsWithSecurityUpdates": { - "label": "Näytä isännät, joilla on tietoturvapäivityksiä", - "description": "Näytä isännät, jotka tarvitsevat tietoturvakorjauksia" - }, - "showRecentUpdates24h": { - "label": "Näytä viimeaikaiset päivitykset (24 h)", - "description": "Näytä viimeisen 24 tunnin aikana asennettujen päivitysten määrä" - }, - "showTotalOutdatedPackages": { - "label": "Näytä vanhentuneet paketit", - "description": "Näytä vanhentuneiden pakettien kokonaismäärä kaikissa isännissä" - }, - "showTotalRepos": { - "label": "Näytä repositoriot", - "description": "Näytä valvottavien aktiivisten repositorioiden määrä" - }, - "enableThresholdColors": { - "label": "Ota käyttöön kynnysarvovärit", - "description": "Väritä tilastoarvot vihreäksi, keltaiseksi tai punaiseksi vakavuusesiasetusten perusteella" - }, - "useCustomThresholds": { - "label": "Edistyneet kynnysarvot", - "description": "Mukauta varoitus- ja kriittiset kynnysarvot tilastoittain käyttäen absoluuttisia määriä tai prosenttiosuutta isäntien kokonaismäärästä" - }, - "thresholdMode": { - "option": { - "absolute": "Absoluuttinen määrä", - "percent": "Prosenttia isäntien kokonaismäärästä" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "Päivityksiä tarvitsevien kynnysarvotila", - "description": "Vertaa päivitystarpeiden määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "Päivitystarpeiden varoituskynnysarvo", - "description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "Päivitystarpeiden kriittinen kynnysarvo", - "description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon" - }, - "securityUpdatesThresholdMode": { - "label": "Tietoturvapäivitysten kynnysarvotila", - "description": "Vertaa tietoturvapäivitysten määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä" - }, - "securityUpdatesWarningAt": { - "label": "Tietoturvapäivitysten varoituskynnysarvo", - "description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon" - }, - "securityUpdatesCriticalAt": { - "label": "Tietoturvapäivitysten kriittinen kynnysarvo", - "description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "Tietoturvapäivityksiä sisältävien isäntien kynnysarvotila", - "description": "Vertaa isäntien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "Tietoturvapäivityksiä sisältävien isäntien varoituskynnysarvo", - "description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "Tietoturvapäivityksiä sisältävien isäntien kriittinen kynnysarvo", - "description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon" - }, - "upToDateHostsThresholdMode": { - "label": "Ajan tasalla olevien isäntien kynnysarvotila", - "description": "Vertaa ajan tasalla olevien isäntien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä" - }, - "upToDateHostsWarningAt": { - "label": "Ajan tasalla olevien isäntien varoituskynnysarvo", - "description": "Muuta keltaiseksi, kun arvo on vähintään tämä kynnysarvo, mutta alle täyden kattavuuden" - }, - "upToDateHostsCriticalAt": { - "label": "Ajan tasalla olevien isäntien kriittinen kynnysarvo", - "description": "Muuta punaiseksi, kun arvo laskee tämän kynnysarvon alle" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "Vanhentuneiden pakettien kynnysarvotila", - "description": "Vertaa vanhentuneiden pakettien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä" - }, - "totalOutdatedPackagesWarningAt": { - "label": "Vanhentuneiden pakettien varoituskynnysarvo", - "description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "Vanhentuneiden pakettien kriittinen kynnysarvo", - "description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon" - }, - "showOsDistribution": { - "label": "Näytä käyttöjärjestelmäjakauma", - "description": "Näytä erittely valvotuista isännistä käyttöjärjestelmittäin" - }, - "osDistributionLimit": { - "label": "Käyttöjärjestelmäjakauman rajoitus", - "description": "Näytettävien käyttöjärjestelmien enimmäismäärä", - "option": { - "3": "3 parasta", - "5": "5 parasta", - "10": "10 parasta", - "all": "Kaikki" - } - }, - "showOsVersion": { - "label": "Näytä käyttöjärjestelmän versio", - "description": "Liitä käyttöjärjestelmän versio jokaiseen jakauman nimikkeeseen, kun se on saatavilla" - }, - "showComplianceHero": { - "label": "Näytä compliance-hero", - "description": "Näytä vaatimustenmukaisuusrengas, joka näyttää ajan tasalla olevien isäntien prosenttiosuuden" - }, - "osDisplayMode": { - "label": "Käyttöjärjestelmän näyttötila", - "description": "Valitse, miten käyttöjärjestelmän jakelu näytetään", - "option": { - "bars": "Vaakapalkit", - "donut": "Donitsikaavio" - } - } - }, - "error": { - "internalServerError": "PatchMon-tietojen nouto epäonnistui" - } - }, - "bazarr": { - "name": "Bazarr", - "description": "Yleiskatsaus puuttuvista tekstityksistä ja terveystilasta Bazarr-instanssistasi", - "episodes": "Puuttuvat jaksot", - "movies": "Puuttuvat elokuvat", - "providers": "Palveluntarjoajan ongelmat", - "status": "Terveysongelmat", - "option": { - "showMissingEpisodes": { - "label": "Näytä puuttuvat jaksot", - "description": "Näytä niiden jaksojen määrä, joista puuttuu tekstitys" - }, - "showMissingMovies": { - "label": "Näytä puuttuvat elokuvat", - "description": "Näytä niiden elokuvien määrä, joista puuttuu tekstitykset" - }, - "showProviderIssues": { - "label": "Näytä tarjoajien ongelmat", - "description": "Näytä ongelmallisten tekstitystarjoajien määrä" - }, - "showHealthIssues": { - "label": "Näytä kunto-ongelmat", - "description": "Näytä Bazarrin kunto-ongelmien määrä" - } - }, - "error": { - "internalServerError": "Bazarrin tietojen nouto epäonnistui" - } - }, "immich-serverStats": { "name": "", "description": "", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "Puuttuva & jonossa oleva media", - "description": "Näyttää puuttuvat ja jonossa olevat elokuvat ja jaksot Radarr:sta ja Sonarr:sta", - "option": { - "showMissing": { - "label": "Näytä puuttuvat kohteet" - }, - "showQueued": { - "label": "Näytä jonossa olevat kohteet" - }, - "pageSize": { - "label": "Kohteita per sivu" - } - }, - "tab": { - "missing": "Puuttuvat", - "queued": "Jonossa" - }, - "type": { - "movie": "Elokuva", - "episode": "Jakso" - }, - "empty": { - "missing": "Ei puuttuvia kohteita", - "queued": "Ei jonossa olevia kohteita", - "noTabsEnabled": "Ota käyttöön vähintään yksi välilehti widgetin asetuksissa" - }, - "timeLeft": "Jäljellä oleva aika" - }, "rssFeed": { "name": "", "description": "", @@ -3744,40 +3323,6 @@ "internalServerError": "Käytettävyystietojen haku epäonnistui" } }, - "traefik": { - "name": "Traefik", - "description": "Yleiskatsaus Traefikin reitittimistä, palveluista, middlewareista ja sisääntulopisteistä", - "option": { - "showTcp": { - "label": "Näytä TCP" - }, - "showUdp": { - "label": "Näytä UDP" - }, - "showEntryPoints": { - "label": "Näytä sisääntulopisteet" - } - }, - "instances": "Traefik-instanssit", - "versionUnknown": "Versio tuntematon", - "summary": { - "routers": "Reitittimet", - "entryPoints": "Sisääntulopisteet" - }, - "resource": { - "routers": "Reitittimet", - "services": "Palvelut", - "middlewares": "Middlewaret" - }, - "status": { - "healthy": "Terve", - "errors": "{count} virhettä", - "warnings": "{count} varoitusta" - }, - "error": { - "internalServerError": "Traefikin tietojen nouto epäonnistui" - } - }, "audioStats": { "name": "Äänitilastot", "description": "Kirjasto- ja toistotilastot Navidromesta tai Audiobookshelfistä", @@ -3901,26 +3446,6 @@ "unhealthy": "" } }, - "customApi": { - "name": "Mukautettu API", - "description": "Näytä dataa mistä tahansa ulkoisesta API:sta mukautetuilla asetuksilla.", - "option": { - "definitionId": { - "label": "Määritelmän tunnus" - }, - "refreshInterval": { - "label": "Päivitysväli", - "description": "Kuinka usein data haetaan uudelleen API:sta (sekunteina)" - } - }, - "noDefinition": "Määritelmää ei valittu", - "definitionNotFound": "Widget-määritelmää ei löydy. Se on saatettu poistaa.", - "noDisplayOutput": "Ei näyttötulostetta", - "executeConfirm": "Haluatko varmasti suorittaa tämän toiminnon?", - "executing": "Suoritetaan...", - "executeSuccess": "Toiminto suoritettu onnistuneesti", - "executeFailed": "Toiminto epäonnistui. Tarkista widgetin asetukset." - }, "beszelSystemTable": { "name": "Beszel-järjestelmät (taulukko)", "description": "Taulukkonäkymä kaikista Beszel-valvotuista järjestelmistä, lajiteltavilla sarakkeilla ja tilaindikaattoreilla", @@ -4171,6 +3696,256 @@ "subtitle": "Docker-konttien verkkoliikenne" } } + }, + "patchmon": { + "name": "PatchMon", + "description": "Yleiskatsaus isäntien päivitystilanteesta PatchMonista", + "title": "PatchMon-tilastot", + "totalHosts": "Isännät yhteensä", + "hostsNeedingUpdates": "Päivitystä tarvitsevat", + "securityUpdates": "Tietoturvapäivitykset", + "upToDateHosts": "Ajan tasalla olevat isännät", + "hostsWithSecurityUpdates": "Isännät, joilla on tietoturvapäivityksiä", + "recentUpdates24h": "Päivitykset (24 h)", + "totalOutdatedPackages": "Vanhentuneet paketit", + "totalRepos": "Pakettivarastot", + "osDistribution": "Käyttöjärjestelmien jakauma", + "compliance": "Päivityskattavuus", + "complianceRatio": "{upToDate} / {total}", + "lastUpdated": "Päivitetty {time}", + "option": { + "showTotalHosts": { + "label": "Näytä isännät yhteensä", + "description": "Näytä valvottujen isäntien kokonaismäärä" + }, + "showHostsNeedingUpdates": { + "label": "Näytä päivitystä tarvitsevat isännät", + "description": "Näytä isännät, joilla on vähintään yksi vanhentunut paketti" + }, + "showSecurityUpdates": { + "label": "Näytä tietoturvapäivitykset", + "description": "Näytä saatavilla olevien tietoturvapäivitysten kokonaismäärä" + }, + "showUpToDateHosts": { + "label": "Näytä ajan tasalla olevat isännät", + "description": "Näytä isännät, joissa ei ole vanhentuneita paketteja" + }, + "showHostsWithSecurityUpdates": { + "label": "Näytä isännät, joilla on tietoturvapäivityksiä", + "description": "Näytä isännät, jotka tarvitsevat tietoturvakorjauksia" + }, + "showRecentUpdates24h": { + "label": "Näytä viimeaikaiset päivitykset (24 h)", + "description": "Näytä viimeisen 24 tunnin aikana asennettujen päivitysten määrä" + }, + "showTotalOutdatedPackages": { + "label": "Näytä vanhentuneet paketit", + "description": "Näytä vanhentuneiden pakettien kokonaismäärä kaikissa isännissä" + }, + "showTotalRepos": { + "label": "Näytä repositoriot", + "description": "Näytä valvottavien aktiivisten repositorioiden määrä" + }, + "enableThresholdColors": { + "label": "Ota käyttöön kynnysarvovärit", + "description": "Väritä tilastoarvot vihreäksi, keltaiseksi tai punaiseksi vakavuusesiasetusten perusteella" + }, + "useCustomThresholds": { + "label": "Edistyneet kynnysarvot", + "description": "Mukauta varoitus- ja kriittiset kynnysarvot tilastoittain käyttäen absoluuttisia määriä tai prosenttiosuutta isäntien kokonaismäärästä" + }, + "thresholdMode": { + "option": { + "absolute": "Absoluuttinen määrä", + "percent": "Prosenttia isäntien kokonaismäärästä" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "Päivityksiä tarvitsevien kynnysarvotila", + "description": "Vertaa päivitystarpeiden määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "Päivitystarpeiden varoituskynnysarvo", + "description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "Päivitystarpeiden kriittinen kynnysarvo", + "description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon" + }, + "securityUpdatesThresholdMode": { + "label": "Tietoturvapäivitysten kynnysarvotila", + "description": "Vertaa tietoturvapäivitysten määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä" + }, + "securityUpdatesWarningAt": { + "label": "Tietoturvapäivitysten varoituskynnysarvo", + "description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon" + }, + "securityUpdatesCriticalAt": { + "label": "Tietoturvapäivitysten kriittinen kynnysarvo", + "description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "Tietoturvapäivityksiä sisältävien isäntien kynnysarvotila", + "description": "Vertaa isäntien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "Tietoturvapäivityksiä sisältävien isäntien varoituskynnysarvo", + "description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "Tietoturvapäivityksiä sisältävien isäntien kriittinen kynnysarvo", + "description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon" + }, + "upToDateHostsThresholdMode": { + "label": "Ajan tasalla olevien isäntien kynnysarvotila", + "description": "Vertaa ajan tasalla olevien isäntien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä" + }, + "upToDateHostsWarningAt": { + "label": "Ajan tasalla olevien isäntien varoituskynnysarvo", + "description": "Muuta keltaiseksi, kun arvo on vähintään tämä kynnysarvo, mutta alle täyden kattavuuden" + }, + "upToDateHostsCriticalAt": { + "label": "Ajan tasalla olevien isäntien kriittinen kynnysarvo", + "description": "Muuta punaiseksi, kun arvo laskee tämän kynnysarvon alle" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "Vanhentuneiden pakettien kynnysarvotila", + "description": "Vertaa vanhentuneiden pakettien määrää absoluuttisena arvona tai prosenttiosuutena isäntien kokonaismäärästä" + }, + "totalOutdatedPackagesWarningAt": { + "label": "Vanhentuneiden pakettien varoituskynnysarvo", + "description": "Muuta keltaiseksi, kun arvo saavuttaa tämän kynnysarvon" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "Vanhentuneiden pakettien kriittinen kynnysarvo", + "description": "Muuta punaiseksi, kun arvo saavuttaa tämän kynnysarvon" + }, + "showOsDistribution": { + "label": "Näytä käyttöjärjestelmäjakauma", + "description": "Näytä erittely valvotuista isännistä käyttöjärjestelmittäin" + }, + "osDistributionLimit": { + "label": "Käyttöjärjestelmäjakauman rajoitus", + "description": "Näytettävien käyttöjärjestelmien enimmäismäärä", + "option": { + "3": "3 parasta", + "5": "5 parasta", + "10": "10 parasta", + "all": "Kaikki" + } + }, + "showOsVersion": { + "label": "Näytä käyttöjärjestelmän versio", + "description": "Liitä käyttöjärjestelmän versio jokaiseen jakauman nimikkeeseen, kun se on saatavilla" + }, + "showComplianceHero": { + "label": "Näytä compliance-hero", + "description": "Näytä vaatimustenmukaisuusrengas, joka näyttää ajan tasalla olevien isäntien prosenttiosuuden" + }, + "osDisplayMode": { + "label": "Käyttöjärjestelmän näyttötila", + "description": "Valitse, miten käyttöjärjestelmän jakelu näytetään", + "option": { + "bars": "Vaakapalkit", + "donut": "Donitsikaavio" + } + } + }, + "error": { + "internalServerError": "PatchMon-tietojen nouto epäonnistui" + } + }, + "bazarr": { + "name": "Bazarr", + "description": "Yleiskatsaus puuttuvista tekstityksistä ja terveystilasta Bazarr-instanssistasi", + "episodes": "Puuttuvat jaksot", + "movies": "Puuttuvat elokuvat", + "providers": "Palveluntarjoajan ongelmat", + "status": "Terveysongelmat", + "option": { + "showMissingEpisodes": { + "label": "Näytä puuttuvat jaksot", + "description": "Näytä niiden jaksojen määrä, joista puuttuu tekstitys" + }, + "showMissingMovies": { + "label": "Näytä puuttuvat elokuvat", + "description": "Näytä niiden elokuvien määrä, joista puuttuu tekstitykset" + }, + "showProviderIssues": { + "label": "Näytä tarjoajien ongelmat", + "description": "Näytä ongelmallisten tekstitystarjoajien määrä" + }, + "showHealthIssues": { + "label": "Näytä kunto-ongelmat", + "description": "Näytä Bazarrin kunto-ongelmien määrä" + } + }, + "error": { + "internalServerError": "Bazarrin tietojen nouto epäonnistui" + } + }, + "mediaMissing": { + "name": "Puuttuva & jonossa oleva media", + "description": "Näyttää puuttuvat ja jonossa olevat elokuvat ja jaksot Radarr:sta ja Sonarr:sta", + "option": { + "showMissing": { + "label": "Näytä puuttuvat kohteet" + }, + "showQueued": { + "label": "Näytä jonossa olevat kohteet" + }, + "pageSize": { + "label": "Kohteita per sivu" + } + }, + "tab": { + "missing": "Puuttuvat", + "queued": "Jonossa" + }, + "type": { + "movie": "Elokuva", + "episode": "Jakso" + }, + "empty": { + "missing": "Ei puuttuvia kohteita", + "queued": "Ei jonossa olevia kohteita", + "noTabsEnabled": "Ota käyttöön vähintään yksi välilehti widgetin asetuksissa" + }, + "timeLeft": "Jäljellä oleva aika" + }, + "traefik": { + "name": "Traefik", + "description": "Yleiskatsaus Traefikin reitittimistä, palveluista, middlewareista ja sisääntulopisteistä", + "option": { + "showTcp": { + "label": "Näytä TCP" + }, + "showUdp": { + "label": "Näytä UDP" + }, + "showEntryPoints": { + "label": "Näytä sisääntulopisteet" + } + }, + "instances": "Traefik-instanssit", + "versionUnknown": "Versio tuntematon", + "summary": { + "routers": "Reitittimet", + "entryPoints": "Sisääntulopisteet" + }, + "resource": { + "routers": "Reitittimet", + "services": "Palvelut", + "middlewares": "Middlewaret" + }, + "status": { + "healthy": "Terve", + "errors": "{count} virhettä", + "warnings": "{count} varoitusta" + }, + "error": { + "internalServerError": "Traefikin tietojen nouto epäonnistui" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Aloitus", "boards": "Paneelit", "apps": "Sovellukset", "integrations": "Integraatiot", - "customWidgets": "Mukautetut widgetit", "searchEngies": "Hakukoneet", "medias": "Mediatiedostot", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "", "boards": { "label": "Paneelit" @@ -5728,18 +5506,6 @@ "label": "Muokkaa" } }, - "custom-widgets": { - "label": "Mukautetut widgetit", - "new": { - "label": "Uusi" - }, - "edit": { - "label": "Muokkaa", - "flow": { - "label": "Kulku" - } - } - }, "users": { "label": "Käyttäjät", "create": { diff --git a/packages/translation/src/lang/fr.json b/packages/translation/src/lang/fr.json index 9c73c03c2..69595c004 100644 --- a/packages/translation/src/lang/fr.json +++ b/packages/translation/src/lang/fr.json @@ -710,14 +710,7 @@ "delete": "Supprimer le widget personnalisé", "deleteConfirm": "Êtes-vous sûr de vouloir supprimer \"{name}\" ? Cette action est irréversible.", "export": "Exporter", - "addMapping": "Ajouter une correspondance", - "addColumn": "Ajouter une colonne", "edit": "Modifier", - "removeMapping": "Supprimer la correspondance", - "removeColumn": "Supprimer la colonne", - "addItem": "Ajouter un élément", - "removeItem": "Supprimer l'élément", - "addBar": "Ajouter une barre", "duplicate": "Dupliquer", "copyAiPrompt": "Copier le prompt IA", "enable": "Activer", @@ -727,150 +720,13 @@ "field": { "name": "Nom", "description": "Description", - "iconUrl": "URL de l'icône", - "url": "URL", - "authType": "Type d’authentification", - "headerName": "Nom du paramètre de l'entête/requête", - "method": "Méthode", - "requestBody": "Corps de la requête", - "displayType": "Type d'affichage", - "jsonPath": "Chemin JSON", - "jsonPathHint": "Utiliser la syntaxe JSONPath pour extraire des valeurs, par exemple $.data.temperature ou $.items[0].name", - "label": "Étiquette", - "unit": "Unité", - "mappings": "Correspondances", - "tablePath": "", - "tablePathHint": "", - "columns": "Colonnes", - "header": "En-tête", - "items": "Objets", - "gridColumns": "Nombre de colonnes", - "cardStyle": "Style des cartes", - "bars": "Barres", - "valuePath": "", - "maxPath": "", - "showPercentage": "Afficher le pourcentage", - "barSize": "Taille de la barre", - "goodValues": "Bonnes valeurs (séparées par des virgules)", - "dotSize": "Taille des points", - "valueSize": "Taille", - "labelPosition": "Position du libellé", - "kvLayout": "", - "striped": "", - "compact": "Mode Compact", - "maxHeight": "", - "color": "Couleur", - "buttonLabel": "", - "buttonColor": "", - "confirmText": "Texte de confirmation", - "confirmTextHint": "", - "successMessage": "Message de réussite", - "successMessageHint": "", - "enabled": "Activé", - "template": { - "label": "Template JSX", - "description": "" - } - }, - "placeholder": { - "exampleLabel": "Température du CPU", - "exampleLabelShort": "Température du CPU", - "exampleHeader": "Nom", - "exampleUnit": "°C", - "iconUrl": "https://...", - "url": "https://api.example.com/api/v1/status", - "headerName": "", - "jsonPath": "$.data.value", - "tablePath": "", - "columnJsonPath": "", - "valuePath": "", - "maxPath": "", - "goodValues": "", - "color": "" - }, - "cardStyleOption": { - "filled": "", - "outline": "", - "subtle": "" - }, - "layoutOption": { - "list": "", - "grid": "" - }, - "sizeOption": { - "sm": "Petit", - "md": "Moyen", - "lg": "Grand", - "xl": "Très grand" - }, - "labelPositionOption": { - "above": "Au-dessus", - "below": "En dessous" - }, - "fieldset": { - "general": "Général", - "connection": "Connexion API", - "display": "Configuration de l'affichage" - }, - "displayTypeDescription": { - "singleValue": "Afficher une valeur extraite avec une étiquette et une unité", - "keyValue": "Afficher plusieurs valeurs étiquetées côte à côte", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "Points d'état colorés montrant en ligne/hors ligne ou l'état de santé", - "countGrid": "", - "raw": "", - "actionButton": "Un bouton qui déclenche une requête lorsqu'elle est cliquée", - "customJsx": "" - }, - "method": { - "GET": "GET", - "POST": "POST", - "PUT": "PUT", - "DELETE": "DELETE", - "PATCH": "PATCH" - }, - "authType": { - "none": "Aucun", - "bearer": "Jeton Bearer", - "basic": "Authentification basique", - "apiKeyHeader": "Clé API (En-tête)", - "apiKeyQuery": "Clé API (requête)" - }, - "displayType": { - "singleValue": "Valeur unique", - "keyValue": "Clé-Valeur", - "table": "Tableau", - "statGrid": "Grille de statistiques", - "progressBars": "Barre de progression", - "statusIndicator": "Indicateur de statut", - "countGrid": "Grille de valeurs", - "raw": "Raw JSON", - "actionButton": "Bouton d'action", - "customJsx": "JSX personnalisé" - }, - "secret": { - "apiKey": "", - "username": "Nom d'utilisateur", - "password": "Mot de passe", - "savedPlaceholder": "" - }, - "preview": { - "title": "Aperçu", - "test": "Tester", - "hint": "Cliquez sur Test pour prévisualiser la réponse API avec votre configuration actuelle.", - "rawResponse": "" + "iconUrl": "URL de l'icône" }, "notification": { "created": "Widget \"{name}\" créé avec succès.", "updated": "Widget \"{name}\" mis à jour avec succès.", "deleted": "Widget \"{name}\" supprimé.", "imported": "Widget importé avec succès.", - "aiPromptCopied": "", - "aiPromptDescription": "", - "aiPromptCopy": "Copier dans le presse-papiers", - "aiPromptNoResponse": "", "aiPromptCopyError": "Échec de la copie du prompt dans le presse-papiers. Votre navigateur peut ne pas prendre en charge cette fonctionnalité.", "createError": "Impossible de créer le widget. Vérifiez que votre point de terminaison API est joignable.", "updateError": "Impossible de mettre à jour le widget. Vos modifications n'ont pas été enregistrées.", @@ -883,14 +739,6 @@ "previewError": "Impossible de récupérer l'aperçu. Vérifiez l'URL et réessayez.", "executed": "Action exécutée avec succès.", "executeError": "Échec de l'action: {error}" - }, - "table": { - "name": "Nom", - "url": "URL", - "display": "Affichage" - }, - "widget": { - "disabled": "Ce widget est désactivé" } }, "integration": { @@ -2828,193 +2676,6 @@ "internalServerError": "" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "Statistiques du serveur Immich", "description": "Informations sur votre instance Immich", @@ -3387,35 +3048,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "Flux RSS", "description": "Surveiller et afficher un ou plusieurs flux RSS, ATOM ou JSON génériques", @@ -3744,40 +3376,6 @@ "internalServerError": "Impossible de récupérer les données de disponibilité" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "Statistiques audio", "description": "", @@ -3901,26 +3499,6 @@ "unhealthy": "Dysfonctionnement" } }, - "customApi": { - "name": "", - "description": "", - "option": { - "definitionId": { - "label": "" - }, - "refreshInterval": { - "label": "", - "description": "" - } - }, - "noDefinition": "", - "definitionNotFound": "", - "noDisplayOutput": "", - "executeConfirm": "", - "executing": "", - "executeSuccess": "", - "executeFailed": "" - }, "beszelSystemTable": { "name": "Systèmes Beszel (Tableau)", "description": "Vue en tableau de tous les systèmes surveillés par Beszel avec colonnes triables et indicateurs d'état", @@ -4171,6 +3749,256 @@ "subtitle": "" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4379,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Accueil", "boards": "Tableaux de bord", "apps": "Applications", "integrations": "Intégrations", - "customWidgets": "Widgets personnalisés", "searchEngies": "Moteurs de recherche", "medias": "Médias", "users": { @@ -5694,6 +5522,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Gérer", "boards": { "label": "Tableaux de bord" @@ -5728,18 +5559,6 @@ "label": "Modifier" } }, - "custom-widgets": { - "label": "Widgets personnalisés", - "new": { - "label": "Nouveau" - }, - "edit": { - "label": "", - "flow": { - "label": "" - } - } - }, "users": { "label": "Utilisateurs", "create": { diff --git a/packages/translation/src/lang/hr.json b/packages/translation/src/lang/hr.json index 536865656..62ea41156 100644 --- a/packages/translation/src/lang/hr.json +++ b/packages/translation/src/lang/hr.json @@ -688,211 +688,6 @@ "add": "" } }, - "customWidget": { - "page": { - "list": { - "title": "", - "noResults": "", - "loading": "" - }, - "create": { - "title": "", - "subtitle": "" - }, - "edit": { - "title": "" - } - }, - "action": { - "create": "", - "import": "", - "save": "", - "delete": "", - "deleteConfirm": "", - "export": "", - "addMapping": "", - "addColumn": "", - "edit": "", - "removeMapping": "", - "removeColumn": "", - "addItem": "", - "removeItem": "", - "addBar": "", - "duplicate": "", - "copyAiPrompt": "", - "enable": "", - "disable": "", - "menu": "" - }, - "field": { - "name": "", - "description": "", - "iconUrl": "", - "url": "", - "authType": "", - "headerName": "", - "method": "", - "requestBody": "", - "displayType": "", - "jsonPath": "", - "jsonPathHint": "", - "label": "", - "unit": "", - "mappings": "", - "tablePath": "", - "tablePathHint": "", - "columns": "", - "header": "", - "items": "", - "gridColumns": "", - "cardStyle": "", - "bars": "", - "valuePath": "", - "maxPath": "", - "showPercentage": "", - "barSize": "", - "goodValues": "", - "dotSize": "", - "valueSize": "", - "labelPosition": "", - "kvLayout": "", - "striped": "", - "compact": "", - "maxHeight": "", - "color": "", - "buttonLabel": "", - "buttonColor": "", - "confirmText": "", - "confirmTextHint": "", - "successMessage": "", - "successMessageHint": "", - "enabled": "", - "template": { - "label": "", - "description": "" - } - }, - "placeholder": { - "exampleLabel": "", - "exampleLabelShort": "", - "exampleHeader": "", - "exampleUnit": "", - "iconUrl": "", - "url": "", - "headerName": "", - "jsonPath": "", - "tablePath": "", - "columnJsonPath": "", - "valuePath": "", - "maxPath": "", - "goodValues": "", - "color": "" - }, - "cardStyleOption": { - "filled": "", - "outline": "", - "subtle": "" - }, - "layoutOption": { - "list": "", - "grid": "" - }, - "sizeOption": { - "sm": "", - "md": "", - "lg": "", - "xl": "" - }, - "labelPositionOption": { - "above": "", - "below": "" - }, - "fieldset": { - "general": "", - "connection": "", - "display": "" - }, - "displayTypeDescription": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "method": { - "GET": "", - "POST": "", - "PUT": "", - "DELETE": "", - "PATCH": "" - }, - "authType": { - "none": "", - "bearer": "", - "basic": "", - "apiKeyHeader": "", - "apiKeyQuery": "" - }, - "displayType": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "secret": { - "apiKey": "", - "username": "", - "password": "", - "savedPlaceholder": "" - }, - "preview": { - "title": "", - "test": "", - "hint": "", - "rawResponse": "" - }, - "notification": { - "created": "", - "updated": "", - "deleted": "", - "imported": "", - "aiPromptCopied": "", - "aiPromptDescription": "", - "aiPromptCopy": "", - "aiPromptNoResponse": "", - "aiPromptCopyError": "", - "createError": "", - "updateError": "", - "importError": "", - "exportError": "", - "duplicated": "", - "duplicateError": "", - "toggleError": "", - "deleteError": "", - "previewError": "", - "executed": "", - "executeError": "" - }, - "table": { - "name": "", - "url": "", - "display": "" - }, - "widget": { - "disabled": "" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "", "description": "", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "RSS kanali", "description": "Pratite i prikazujte jedan ili više općih RSS, ATOM ili JSON kanala", @@ -3744,40 +3323,6 @@ "internalServerError": "" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "", "description": "", @@ -3901,26 +3446,6 @@ "unhealthy": "" } }, - "customApi": { - "name": "", - "description": "", - "option": { - "definitionId": { - "label": "" - }, - "refreshInterval": { - "label": "", - "description": "" - } - }, - "noDefinition": "", - "definitionNotFound": "", - "noDisplayOutput": "", - "executeConfirm": "", - "executing": "", - "executeSuccess": "", - "executeFailed": "" - }, "beszelSystemTable": { "name": "Beszel sustavi (tablica)", "description": "Tablični prikaz svih Beszel nadziranih sustava s sortabilnim stupcima i indikatorima statusa", @@ -4171,6 +3696,256 @@ "subtitle": "" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Dom", "boards": "Daske", "apps": "aplikacije", "integrations": "Integracije", - "customWidgets": "", "searchEngies": "Tražilice", "medias": "Mediji", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Upravljati", "boards": { "label": "Daske" @@ -5728,18 +5506,6 @@ "label": "Uredi" } }, - "custom-widgets": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "", - "flow": { - "label": "" - } - } - }, "users": { "label": "Korisnici", "create": { diff --git a/packages/translation/src/lang/hu.json b/packages/translation/src/lang/hu.json index 979b24bce..fd5a5cc48 100644 --- a/packages/translation/src/lang/hu.json +++ b/packages/translation/src/lang/hu.json @@ -688,211 +688,6 @@ "add": "Alkalmazás hozzáadása" } }, - "customWidget": { - "page": { - "list": { - "title": "Egyéni widgetek", - "noResults": "Még nincsenek egyéni widgetek. Hozd létre az elsőt!", - "loading": "Töltés..." - }, - "create": { - "title": "Egyéni widget létrehozása", - "subtitle": "Adj meg egy API URL-t, hitelesítést, és hogy hogyan jelenjenek meg a válaszadatok." - }, - "edit": { - "title": "Egyéni widget szerkesztése" - } - }, - "action": { - "create": "Létrehozás", - "import": "Importálás", - "save": "Mentés", - "delete": "Egyéni widget törlése", - "deleteConfirm": "Biztosan törölni szeretnéd \"{name}\" widgetet? Ez a művelet nem vonható vissza.", - "export": "Exportálás", - "addMapping": "Leképezés hozzáadása", - "addColumn": "Oszlop hozzáadása", - "edit": "Szerkesztés", - "removeMapping": "Leképezés eltávolítása", - "removeColumn": "Oszlop eltávolítása", - "addItem": "Elem hozzáadása", - "removeItem": "Elem eltávolítása", - "addBar": "Sáv hozzáadása", - "duplicate": "Duplikálás", - "copyAiPrompt": "AI prompt másolása", - "enable": "Engedélyezés", - "disable": "Letiltás", - "menu": "Műveletek" - }, - "field": { - "name": "Név", - "description": "Leírás", - "iconUrl": "Ikon URL", - "url": "URL", - "authType": "Hitelesítés típusa", - "headerName": "Fejléc/lekérdezési paraméter neve", - "method": "Metódus", - "requestBody": "Kérelem törzse", - "displayType": "Megjelenítés típusa", - "jsonPath": "JSON elérési út", - "jsonPathHint": "Használd a JSONPath szintaxist az értékek kinyeréséhez, pl. $.data.temperature vagy $.items[0].name", - "label": "Címke", - "unit": "Mértékegység", - "mappings": "Leképezések", - "tablePath": "Tömb JSON elérési útja", - "tablePathHint": "A válaszban lévő tömb elérési útja, pl. $.data.items", - "columns": "Oszlopok", - "header": "Fejléc", - "items": "Elemek", - "gridColumns": "Rács oszlopok", - "cardStyle": "Kártya stílus", - "bars": "Sávok", - "valuePath": "Érték JSON elérési út", - "maxPath": "Maximális érték JSON elérési út", - "showPercentage": "Százalék megjelenítése", - "barSize": "Sáv mérete", - "goodValues": "Jó értékek (vesszővel elválasztva)", - "dotSize": "Pont mérete", - "valueSize": "Érték mérete", - "labelPosition": "Címke pozíciója", - "kvLayout": "Elrendezés", - "striped": "Csíkos sorok", - "compact": "Kompakt mód", - "maxHeight": "Maximális magasság (px)", - "color": "Szín", - "buttonLabel": "Gomb felirata", - "buttonColor": "Gomb színe", - "confirmText": "Megerősítő szöveg", - "confirmTextHint": "Ha be van állítva, egy megerősítő ablak jelenik meg a kérés végrehajtása előtt", - "successMessage": "Sikerüzenet", - "successMessageHint": "A sikeres végrehajtás után megjelenő üzenet", - "enabled": "Engedélyezve", - "template": { - "label": "JSX sablon", - "description": "Mantine JSX sablon. Az API válasz mezőit adatkötéseken keresztül éred el (pl. data.name). Csak engedélyezett komponenseket használj. Tilos: constructor, __proto__, eval, Function, window, document." - } - }, - "placeholder": { - "exampleLabel": "CPU hőmérséklet", - "exampleLabelShort": "CPU hőm", - "exampleHeader": "Név", - "exampleUnit": "°C", - "iconUrl": "https://...", - "url": "https://api.example.com/api/v1/status", - "headerName": "X-API-Key", - "jsonPath": "$.data.value", - "tablePath": "$.data.items", - "columnJsonPath": "$.name", - "valuePath": "$.data.used", - "maxPath": "$.data.total", - "goodValues": "online, true, up", - "color": "kék" - }, - "cardStyleOption": { - "filled": "Kitöltött", - "outline": "Körvonal", - "subtle": "Halvány" - }, - "layoutOption": { - "list": "Lista", - "grid": "Rács" - }, - "sizeOption": { - "sm": "Kicsi", - "md": "Közepes", - "lg": "Nagy", - "xl": "Extra nagy" - }, - "labelPositionOption": { - "above": "Felette", - "below": "Alatta" - }, - "fieldset": { - "general": "Általános", - "connection": "API kapcsolat", - "display": "Megjelenítési konfiguráció" - }, - "displayTypeDescription": { - "singleValue": "Egy kinyert érték megjelenítése címkével és mértékegységgel", - "keyValue": "Több címkézett érték megjelenítése egymás mellett", - "table": "Adatsorok megjelenítése táblázatos formában", - "statGrid": "Színezett statisztikai kártyák rácsban – mint a Pi-Hole vagy Speedtest widgetek", - "progressBars": "Folyamatjelző sávok használat vagy készültség mutatására – lemez, memória, kvóta", - "statusIndicator": "Színezett állapotpontok, amelyek online/offline vagy egészségügyi állapotot mutatnak", - "countGrid": "Kompakt szám + címke számlálók sűrű rácsban", - "raw": "Szépen formázott JSON kimenet hibakereséshez", - "actionButton": "Egy gomb, ami kérés végrehajtását váltja ki kattintásra", - "customJsx": "Egyéni JSX elrendezés engedélyezett Mantine komponensekkel és teljes API adatkötéssel" - }, - "method": { - "GET": "GET", - "POST": "POST", - "PUT": "PUT", - "DELETE": "DELETE", - "PATCH": "PATCH" - }, - "authType": { - "none": "Nincs", - "bearer": "Bearer token", - "basic": "Basic Auth", - "apiKeyHeader": "API-kulcs (fejléc)", - "apiKeyQuery": "API-kulcs (lekérdezés)" - }, - "displayType": { - "singleValue": "Egyedi érték", - "keyValue": "Kulcs-érték", - "table": "Táblázat", - "statGrid": "Statisztikai rács", - "progressBars": "Folyamatjelző sávok", - "statusIndicator": "Állapotjelző", - "countGrid": "Számláló rács", - "raw": "Nyers JSON", - "actionButton": "Műveleti gomb", - "customJsx": "Egyéni JSX" - }, - "secret": { - "apiKey": "API kulcs / token", - "username": "Felhasználónév", - "password": "Jelszó", - "savedPlaceholder": "••••••• (mentve, üresen hagyva megtartja)" - }, - "preview": { - "title": "Előnézet", - "test": "Teszt", - "hint": "Kattints a Teszt gombra az API válasz előnézetéhez a jelenlegi konfigurációval.", - "rawResponse": "Nyers JSON válasz" - }, - "notification": { - "created": "\"{name}\" widget sikeresen létrehozva.", - "updated": "\"{name}\" widget sikeresen frissítve.", - "deleted": "\"{name}\" widget törölve.", - "imported": "", - "aiPromptCopied": "AI prompt a vágólapra másolva", - "aiPromptDescription": "Másolj egy előre elkészített promptot bármelyik AI chatbotba (ChatGPT, Claude, Gemini...). Tartalmazza a teljes widget sémát és az API választ, így az AI generálhat egy importálásra kész JSON konfigurációt.", - "aiPromptCopy": "Másolás a vágólapra", - "aiPromptNoResponse": "Tipp: Futtass egy tesztet először, hogy az API válasz is bekerüljön a promptba a jobb eredmények érdekében.", - "aiPromptCopyError": "A prompt vágólapra másolása sikertelen. Előfordulhat, hogy a böngésződ nem támogatja ezt a funkciót.", - "createError": "A widget létrehozása sikertelen. Ellenőrizd, hogy az API végpont elérhető-e.", - "updateError": "A widget frissítése sikertelen. A módosításaid nem lettek mentve.", - "importError": "A widget importálása sikertelen. Ellenőrizd, hogy a fájl érvényes egyéni widget JSON export-e.", - "exportError": "A widget exportálása sikertelen.", - "duplicated": "\"{name}\" widget duplikálva.", - "duplicateError": "A widget duplikálása sikertelen.", - "toggleError": "A widget állapotának átkapcsolása sikertelen.", - "deleteError": "A widget törlése sikertelen.", - "previewError": "Az előnézet lekérése sikertelen. Ellenőrizd az URL-t és próbáld újra.", - "executed": "A művelet sikeresen végrehajtva.", - "executeError": "A művelet sikertelen: {error}" - }, - "table": { - "name": "Név", - "url": "URL", - "display": "Megjelenítés" - }, - "widget": { - "disabled": "Ez a widget le van tiltva" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "A Paperless-ngx adatok letöltése nem sikerült" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "Immich szerver statisztikák", "description": "Információk az Immich-példányodról", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "RSS feedek", "description": "Egy vagy több általános RSS-, ATOM- vagy JSON-hírcsatorna figyelése és megjelenítése", @@ -3744,40 +3323,6 @@ "internalServerError": "Az üzemidőadatok letöltése nem sikerült" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "Audió statisztikák", "description": "Könyvtári és lejátszási statisztikák Navidrome-ból vagy Audiobookshelf-ből", @@ -3901,26 +3446,6 @@ "unhealthy": "Hibás" } }, - "customApi": { - "name": "Egyéni API", - "description": "Adatok megjelenítése bármely külső API-ból egyedi konfigurációval.", - "option": { - "definitionId": { - "label": "Definíció azonosító" - }, - "refreshInterval": { - "label": "Frissítési időköz", - "description": "Milyen gyakran kérje le újra az adatokat az API-tól (másodpercben)" - } - }, - "noDefinition": "Nincs definíció kiválasztva", - "definitionNotFound": "A widget definíció nem található. Lehet, hogy törölték.", - "noDisplayOutput": "Nincs megjelenítési kimenet", - "executeConfirm": "Biztosan végre szeretnéd hajtani ezt a műveletet?", - "executing": "Végrehajtás...", - "executeSuccess": "A művelet sikeresen végrehajtva", - "executeFailed": "A művelet sikertelen. Ellenőrizd a widget konfigurációját." - }, "beszelSystemTable": { "name": "Beszel Rendszerek (Táblázat)", "description": "Az összes Beszel által figyelt rendszer táblázatos nézete rendezhető oszlopokkal és állapotjelzőkkel", @@ -4171,6 +3696,256 @@ "subtitle": "A Docker konténerek hálózati forgalma" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Nyitólap", "boards": "Táblák", "apps": "Alkalmazások", "integrations": "Integrációk", - "customWidgets": "", "searchEngies": "Keresőmotorok", "medias": "Média", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Kezelés", "boards": { "label": "Táblák" @@ -5728,18 +5506,6 @@ "label": "Szerkesztés" } }, - "custom-widgets": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "", - "flow": { - "label": "" - } - } - }, "users": { "label": "Felhasználók", "create": { diff --git a/packages/translation/src/lang/ko.json b/packages/translation/src/lang/ko.json index 9941463ff..08c1da46f 100644 --- a/packages/translation/src/lang/ko.json +++ b/packages/translation/src/lang/ko.json @@ -710,14 +710,7 @@ "delete": "사용자 지정 위젯 삭제", "deleteConfirm": "\"{name}\"을(를) 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", "export": "내보내기", - "addMapping": "매핑 추가", - "addColumn": "열 추가", "edit": "편집", - "removeMapping": "매핑 제거", - "removeColumn": "열 제거", - "addItem": "항목 추가", - "removeItem": "항목 제거", - "addBar": "바 추가", "duplicate": "복사", "copyAiPrompt": "AI 프롬프트 복사", "enable": "활성화", @@ -727,140 +720,7 @@ "field": { "name": "이름", "description": "설명", - "iconUrl": "아이콘 URL", - "url": "URL", - "authType": "인증 유형", - "headerName": "헤더/쿼리 파라미터 이름", - "method": "메서드", - "requestBody": "요청 본문", - "displayType": "표시 유형", - "jsonPath": "JSON 경로", - "jsonPathHint": "JSONPath 문법으로 값을 추출하십시오. 예: $.data.temperature 또는 $.items[0].name", - "label": "레이블", - "unit": "단위", - "mappings": "매핑", - "tablePath": "JSON 경로 배열", - "tablePathHint": "응답에서 배열이 위치한 경로입니다. 예: $.data.items", - "columns": "열", - "header": "헤더", - "items": "항목", - "gridColumns": "그리드 열 개수", - "cardStyle": "카드 스타일", - "bars": "바", - "valuePath": "JSON 경로 값", - "maxPath": "JSON 경로 최댓값", - "showPercentage": "백분율 표시", - "barSize": "바 크기", - "goodValues": "정상 값(쉼표로 구분)", - "dotSize": "점 크기", - "valueSize": "값 크기", - "labelPosition": "레이블 위치", - "kvLayout": "레이아웃", - "striped": "줄무늬 행", - "compact": "컴팩트 모드", - "maxHeight": "최대 높이 (px)", - "color": "색상", - "buttonLabel": "버튼 명칭", - "buttonColor": "버튼 색상", - "confirmText": "확인 텍스트", - "confirmTextHint": "설정하면 요청을 실행하기 전에 확인 대화상자가 표시됩니다", - "successMessage": "성공 메세지", - "successMessageHint": "실행 성공 후 표시되는 메세지", - "enabled": "활성화됨", - "template": { - "label": "JSX 템플릿", - "description": "Mantine JSX 템플릿. 데이터 바인딩(예: data.name)을 통해 API 응답 필드에 액세스합니다. 허용된 구성 요소만 사용하십시오. 금지: constructor, __proto__, eval, Function, window, document." - } - }, - "placeholder": { - "exampleLabel": "CPU 온도", - "exampleLabelShort": "CPU 온도", - "exampleHeader": "이름", - "exampleUnit": "°C", - "iconUrl": "https://...", - "url": "https://api.example.com/api/v1/status", - "headerName": "X-API-Key", - "jsonPath": "$.data.value", - "tablePath": "$.data.items", - "columnJsonPath": "$.name", - "valuePath": "$.data.used", - "maxPath": "$.data.total", - "goodValues": "online, true, up", - "color": "파랑" - }, - "cardStyleOption": { - "filled": "채워짐", - "outline": "외곽선", - "subtle": "미묘한" - }, - "layoutOption": { - "list": "리스트", - "grid": "그리드" - }, - "sizeOption": { - "sm": "작음", - "md": "중간", - "lg": "큼", - "xl": "매우 큼" - }, - "labelPositionOption": { - "above": "위", - "below": "아래" - }, - "fieldset": { - "general": "일반", - "connection": "API 연결", - "display": "표시 설정" - }, - "displayTypeDescription": { - "singleValue": "레이블과 단위가 있는 하나의 추출된 값을 표시합니다", - "keyValue": "여러 레이블이 지정된 값을 나란히 표시합니다", - "table": "테이블 형식으로 데이터 행을 표시합니다", - "statGrid": "그리드의 색상이 지정된 통계 카드 — Pi-Hole 또는 Speedtest 위젯과 유사", - "progressBars": "사용량 또는 완료율을 표시하는 진행률 표시줄 — 디스크, 메모리, 할당량용", - "statusIndicator": "온라인/오프라인 또는 상태를 표시하는 색상 상태 점", - "countGrid": "좁은 그리드에 작은 숫자 + 레이블 카운터", - "raw": "디버깅을 위한 예쁘게 출력된 JSON", - "actionButton": "클릭 시 요청을 트리거하는 버튼", - "customJsx": "전체 API 데이터 바인딩과 함께 허용된 Mantine 구성 요소를 사용하는 사용자 정의 JSX 레이아웃" - }, - "method": { - "GET": "GET", - "POST": "POST", - "PUT": "PUT", - "DELETE": "DELETE", - "PATCH": "PATCH" - }, - "authType": { - "none": "없음", - "bearer": "Bearer 토큰", - "basic": "기본 인증", - "apiKeyHeader": "API 키(헤더)", - "apiKeyQuery": "API 키(쿼리)" - }, - "displayType": { - "singleValue": "단일 값", - "keyValue": "키-값", - "table": "테이블", - "statGrid": "스택 그리드", - "progressBars": "진행 바", - "statusIndicator": "상태 인디케이터", - "countGrid": "카운트 그리드", - "raw": "원시 JSON", - "actionButton": "동작 버튼", - "customJsx": "사용자 지정 JSX" - }, - "secret": { - "apiKey": "API 키/토큰", - "username": "사용자명", - "password": "비밀번호", - "savedPlaceholder": "••••••• (저장됨, 유지하려면 공백)" - }, - "preview": { - "title": "미리보기", - "test": "테스트", - "hint": "현재 설정으로 API 응답을 미리 보려면 테스트를 클릭하십시오.", - "rawResponse": "원본 JSON 응답" + "iconUrl": "아이콘 URL" }, "notification": { "created": "\"{name}\" 위젯 생성 완료.", @@ -868,9 +728,6 @@ "deleted": "\"{name}\" 위젯 삭제 완료.", "imported": "위젯 가져오기 완료.", "aiPromptCopied": "AI 프롬프트 클립보드에 복사됨", - "aiPromptDescription": "사전 제작된 프롬프트를 복사하여 AI 챗봇(ChatGPT, Claude, Gemini 등)에 붙여넣습니다. 전체 위젯 스키마 및 API 응답이 포함되어 있으므로 즉시 가져올 수 있는 JSON 설정을 AI가 생성할 수 있습니다.", - "aiPromptCopy": "클립보드에 복사", - "aiPromptNoResponse": "팁: 더 나은 결과를 얻기 위해 먼저 테스트로 프롬프트에 API 응답을 포함하십시오.", "aiPromptCopyError": "프롬프트 클립보드 복사 실패. 브라우저에서 이 기능을 지원하지 않을 수도 있습니다.", "createError": "위젯 생성 실패. API 엔드포인트에 도달할 수 있는지 확인해 보십시오.", "updateError": "위젯 업데이트 실패. 변경 사항이 저장되지 않습니다.", @@ -883,14 +740,6 @@ "previewError": "미리보기 가져오기 실패. URL을 확인한 후 다시 시도해 주십시오.", "executed": "작업 실행 완료.", "executeError": "작업 실패: {error}" - }, - "table": { - "name": "이름", - "url": "URL", - "display": "표시" - }, - "widget": { - "disabled": "위젯 비활성화됨" } }, "integration": { @@ -2828,193 +2677,6 @@ "internalServerError": "Paperless-ngx 데이터를 가져오지 못함" } }, - "patchmon": { - "name": "PatchMon", - "description": "PatchMon의 호스트 패치 상태 개요", - "title": "PatchMon 통계", - "totalHosts": "총 호스트", - "hostsNeedingUpdates": "업데이트 필요", - "securityUpdates": "보안 업데이트", - "upToDateHosts": "최신 상태의 호스트", - "hostsWithSecurityUpdates": "보안 업데이트가 필요한 호스트", - "recentUpdates24h": "업데이트 (24시간)", - "totalOutdatedPackages": "오래된 패키지", - "totalRepos": "저장소", - "osDistribution": "OS 배포판", - "compliance": "패치 준수", - "complianceRatio": "{upToDate} / {total}", - "lastUpdated": "{time} 업데이트됨", - "option": { - "showTotalHosts": { - "label": "총 호스트 표시", - "description": "모니터링되는 총 호스트 수 표시" - }, - "showHostsNeedingUpdates": { - "label": "업데이트가 필요한 호스트 표시", - "description": "하나 이상의 오래된 패키지가 있는 호스트 표시" - }, - "showSecurityUpdates": { - "label": "보안 업데이트 표시", - "description": "사용 가능한 총 보안 업데이트 수 표시" - }, - "showUpToDateHosts": { - "label": "최신 호스트 표시", - "description": "오래된 패키지가 없는 호스트 표시" - }, - "showHostsWithSecurityUpdates": { - "label": "보안 업데이트가 필요한 호스트 표시", - "description": "보안 패치가 필요한 호스트 표시" - }, - "showRecentUpdates24h": { - "label": "최근 업데이트 (24시간) 표시", - "description": "지난 24시간 동안 적용된 업데이트 수 표시" - }, - "showTotalOutdatedPackages": { - "label": "오래된 패키지 표시", - "description": "모든 호스트에서의 총 오래된 패키지 수 표시" - }, - "showTotalRepos": { - "label": "저장소 표시", - "description": "모니터링되는 활성 저장소 수 표시" - }, - "enableThresholdColors": { - "label": "임계값 색상 활성화", - "description": "심각도 사전 설정에 따라 통계 값을 녹색, 노란색 또는 빨간색으로 표시" - }, - "useCustomThresholds": { - "label": "고급 임계값", - "description": "절대 개수 또는 전체 호스트 대비 백분율을 사용하여 통계별 경고 및 위험 임계값 사용자 정의" - }, - "thresholdMode": { - "option": { - "absolute": "절대 개수", - "percent": "전체 호스트 대비 백분율" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "업데이트 필요 임계값 모드", - "description": "업데이트 필요 개수를 절대값 또는 전체 호스트 대비 백분율로 비교" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "업데이트 필요 경고 임계값", - "description": "이 임계값에 도달하면 노란색으로 표시" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "업데이트 필요 위험 임계값", - "description": "이 임계값에 도달하면 빨간색으로 표시" - }, - "securityUpdatesThresholdMode": { - "label": "보안 업데이트 임계값 모드", - "description": "보안 업데이트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교" - }, - "securityUpdatesWarningAt": { - "label": "보안 업데이트 경고 임계값", - "description": "이 임계값에 도달하면 노란색으로 표시" - }, - "securityUpdatesCriticalAt": { - "label": "보안 업데이트 위험 임계값", - "description": "이 임계값에 도달하면 빨간색으로 표시" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "보안 업데이트가 있는 호스트 임계값 모드", - "description": "호스트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "보안 업데이트가 있는 호스트 경고 임계값", - "description": "이 임계값에 도달하면 노란색으로 표시" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "보안 업데이트가 있는 호스트 위험 임계값", - "description": "이 임계값에 도달하면 빨간색으로 표시" - }, - "upToDateHostsThresholdMode": { - "label": "최신 호스트 임계값 모드", - "description": "최신 호스트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교" - }, - "upToDateHostsWarningAt": { - "label": "최신 호스트 경고 임계값", - "description": "값이 이 임계값 이상이지만 전체 적용 범위 미만일 때 노란색으로 표시" - }, - "upToDateHostsCriticalAt": { - "label": "최신 호스트 위험 임계값", - "description": "값이 이 임계값 미만으로 떨어지면 빨간색으로 표시" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "오래된 패키지 임계값 모드", - "description": "오래된 패키지 개수를 절대값 또는 전체 호스트 대비 백분율로 비교" - }, - "totalOutdatedPackagesWarningAt": { - "label": "오래된 패키지 경고 임계값", - "description": "이 임계값에 도달하면 노란색으로 표시" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "오래된 패키지 위험 임계값", - "description": "이 임계값에 도달하면 빨간색으로 표시" - }, - "showOsDistribution": { - "label": "OS 배포판 표시", - "description": "운영 체제별로 모니터링되는 호스트 분석 표시" - }, - "osDistributionLimit": { - "label": "OS 배포판 제한", - "description": "표시할 최대 운영 체제 수", - "option": { - "3": "상위 3개", - "5": "상위 5개", - "10": "상위 10개", - "all": "모두" - } - }, - "showOsVersion": { - "label": "OS 버전 표시", - "description": "사용 가능한 경우 각 배포판 레이블에 OS 버전 추가" - }, - "showComplianceHero": { - "label": "준수 상태 표시", - "description": "최신 호스트의 백분율을 표시하는 준수 링 표시" - }, - "osDisplayMode": { - "label": "OS 표시 모드", - "description": "운영 체제 배포판 표시 방법 선택", - "option": { - "bars": "가로 막대", - "donut": "도넛 차트" - } - } - }, - "error": { - "internalServerError": "PatchMon 데이터를 가져오지 못했습니다" - } - }, - "bazarr": { - "name": "Bazarr", - "description": "Bazarr 인스턴스의 누락된 자막 및 상태 개요", - "episodes": "누락된 에피소드", - "movies": "누락된 영화", - "providers": "제공자 문제", - "status": "상태 문제", - "option": { - "showMissingEpisodes": { - "label": "누락된 에피소드 표시", - "description": "누락된 자막이 있는 에피소드 수 표시" - }, - "showMissingMovies": { - "label": "누락된 영화 표시", - "description": "누락된 자막이 있는 영화 수 표시" - }, - "showProviderIssues": { - "label": "제공자 문제 표시", - "description": "문제가 있는 자막 제공자 수 표시" - }, - "showHealthIssues": { - "label": "상태 문제 표시", - "description": "Bazarr 상태 문제 수 표시" - } - }, - "error": { - "internalServerError": "Bazarr 데이터를 가져오지 못했습니다" - } - }, "immich-serverStats": { "name": "Immich 서버 정보", "description": "Immich 인스턴스에 대한 정보", @@ -3387,35 +3049,6 @@ } } }, - "mediaMissing": { - "name": "누락 및 대기 중인 미디어", - "description": "Radarr 및 Sonarr의 누락 및 대기 중인 영화와 에피소드 표시", - "option": { - "showMissing": { - "label": "누락된 항목 표시" - }, - "showQueued": { - "label": "대기 중인 항목 표시" - }, - "pageSize": { - "label": "페이지당 항목 수" - } - }, - "tab": { - "missing": "누락", - "queued": "대기 중" - }, - "type": { - "movie": "영화", - "episode": "에피소드" - }, - "empty": { - "missing": "누락된 항목 없음", - "queued": "대기 중인 항목 없음", - "noTabsEnabled": "위젯 설정에서 최소한 하나의 탭을 활성화하세요" - }, - "timeLeft": "남은 시간" - }, "rssFeed": { "name": "RSS 피드", "description": "하나 이상의 일반 RSS, ATOM 또는 JSON 피드를 모니터링하고 표시합니다", @@ -3744,40 +3377,6 @@ "internalServerError": "가동 시간 데이터를 가져오지 못함" } }, - "traefik": { - "name": "Traefik", - "description": "Traefik 라우터, 서비스, 미들웨어 및 진입점 개요", - "option": { - "showTcp": { - "label": "TCP 표시" - }, - "showUdp": { - "label": "UDP 표시" - }, - "showEntryPoints": { - "label": "진입점 표시" - } - }, - "instances": "Traefik 인스턴스", - "versionUnknown": "버전 알 수 없음", - "summary": { - "routers": "라우터", - "entryPoints": "진입점" - }, - "resource": { - "routers": "라우터", - "services": "서비스", - "middlewares": "미들웨어" - }, - "status": { - "healthy": "정상", - "errors": "{count}개 오류", - "warnings": "{count}개 경고" - }, - "error": { - "internalServerError": "Traefik 데이터를 가져오지 못함" - } - }, "audioStats": { "name": "오디오 정보", "description": "Navidrome 또는 Audiobookshelf의 라이브러리 및 재생 정보", @@ -3901,26 +3500,6 @@ "unhealthy": "비정상" } }, - "customApi": { - "name": "사용자 지정 API", - "description": "사용자 지정 설정으로 외부 API 데이터를 표시합니다.", - "option": { - "definitionId": { - "label": "정의 ID" - }, - "refreshInterval": { - "label": "새로고침 간격", - "description": "API에서 데이터를 다시 가져오는 빈도 (초 단위)" - } - }, - "noDefinition": "선택한 정의 없음", - "definitionNotFound": "위젯 정의를 찾을 수 없습니다. 삭제되었을 수 있습니다.", - "noDisplayOutput": "디스플레이 출력 없음", - "executeConfirm": "이 작업을 삭제하시겠습니까?", - "executing": "실행 중...", - "executeSuccess": "작업 실행 완료", - "executeFailed": "작업 실패. 위젯 설정을 확인하십시오." - }, "beszelSystemTable": { "name": "Beszel 시스템 (표)", "description": "정렬 가능한 열과 상태 표시기가 있는 모든 Beszel 모니터링 시스템의 표 보기", @@ -4171,6 +3750,256 @@ "subtitle": "Docker 컨테이너의 네트워크 트래픽" } } + }, + "patchmon": { + "name": "PatchMon", + "description": "PatchMon의 호스트 패치 상태 개요", + "title": "PatchMon 통계", + "totalHosts": "총 호스트", + "hostsNeedingUpdates": "업데이트 필요", + "securityUpdates": "보안 업데이트", + "upToDateHosts": "최신 상태의 호스트", + "hostsWithSecurityUpdates": "보안 업데이트가 필요한 호스트", + "recentUpdates24h": "업데이트 (24시간)", + "totalOutdatedPackages": "오래된 패키지", + "totalRepos": "저장소", + "osDistribution": "OS 배포판", + "compliance": "패치 준수", + "complianceRatio": "{upToDate} / {total}", + "lastUpdated": "{time} 업데이트됨", + "option": { + "showTotalHosts": { + "label": "총 호스트 표시", + "description": "모니터링되는 총 호스트 수 표시" + }, + "showHostsNeedingUpdates": { + "label": "업데이트가 필요한 호스트 표시", + "description": "하나 이상의 오래된 패키지가 있는 호스트 표시" + }, + "showSecurityUpdates": { + "label": "보안 업데이트 표시", + "description": "사용 가능한 총 보안 업데이트 수 표시" + }, + "showUpToDateHosts": { + "label": "최신 호스트 표시", + "description": "오래된 패키지가 없는 호스트 표시" + }, + "showHostsWithSecurityUpdates": { + "label": "보안 업데이트가 필요한 호스트 표시", + "description": "보안 패치가 필요한 호스트 표시" + }, + "showRecentUpdates24h": { + "label": "최근 업데이트 (24시간) 표시", + "description": "지난 24시간 동안 적용된 업데이트 수 표시" + }, + "showTotalOutdatedPackages": { + "label": "오래된 패키지 표시", + "description": "모든 호스트에서의 총 오래된 패키지 수 표시" + }, + "showTotalRepos": { + "label": "저장소 표시", + "description": "모니터링되는 활성 저장소 수 표시" + }, + "enableThresholdColors": { + "label": "임계값 색상 활성화", + "description": "심각도 사전 설정에 따라 통계 값을 녹색, 노란색 또는 빨간색으로 표시" + }, + "useCustomThresholds": { + "label": "고급 임계값", + "description": "절대 개수 또는 전체 호스트 대비 백분율을 사용하여 통계별 경고 및 위험 임계값 사용자 정의" + }, + "thresholdMode": { + "option": { + "absolute": "절대 개수", + "percent": "전체 호스트 대비 백분율" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "업데이트 필요 임계값 모드", + "description": "업데이트 필요 개수를 절대값 또는 전체 호스트 대비 백분율로 비교" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "업데이트 필요 경고 임계값", + "description": "이 임계값에 도달하면 노란색으로 표시" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "업데이트 필요 위험 임계값", + "description": "이 임계값에 도달하면 빨간색으로 표시" + }, + "securityUpdatesThresholdMode": { + "label": "보안 업데이트 임계값 모드", + "description": "보안 업데이트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교" + }, + "securityUpdatesWarningAt": { + "label": "보안 업데이트 경고 임계값", + "description": "이 임계값에 도달하면 노란색으로 표시" + }, + "securityUpdatesCriticalAt": { + "label": "보안 업데이트 위험 임계값", + "description": "이 임계값에 도달하면 빨간색으로 표시" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "보안 업데이트가 있는 호스트 임계값 모드", + "description": "호스트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "보안 업데이트가 있는 호스트 경고 임계값", + "description": "이 임계값에 도달하면 노란색으로 표시" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "보안 업데이트가 있는 호스트 위험 임계값", + "description": "이 임계값에 도달하면 빨간색으로 표시" + }, + "upToDateHostsThresholdMode": { + "label": "최신 호스트 임계값 모드", + "description": "최신 호스트 개수를 절대값 또는 전체 호스트 대비 백분율로 비교" + }, + "upToDateHostsWarningAt": { + "label": "최신 호스트 경고 임계값", + "description": "값이 이 임계값 이상이지만 전체 적용 범위 미만일 때 노란색으로 표시" + }, + "upToDateHostsCriticalAt": { + "label": "최신 호스트 위험 임계값", + "description": "값이 이 임계값 미만으로 떨어지면 빨간색으로 표시" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "오래된 패키지 임계값 모드", + "description": "오래된 패키지 개수를 절대값 또는 전체 호스트 대비 백분율로 비교" + }, + "totalOutdatedPackagesWarningAt": { + "label": "오래된 패키지 경고 임계값", + "description": "이 임계값에 도달하면 노란색으로 표시" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "오래된 패키지 위험 임계값", + "description": "이 임계값에 도달하면 빨간색으로 표시" + }, + "showOsDistribution": { + "label": "OS 배포판 표시", + "description": "운영 체제별로 모니터링되는 호스트 분석 표시" + }, + "osDistributionLimit": { + "label": "OS 배포판 제한", + "description": "표시할 최대 운영 체제 수", + "option": { + "3": "상위 3개", + "5": "상위 5개", + "10": "상위 10개", + "all": "모두" + } + }, + "showOsVersion": { + "label": "OS 버전 표시", + "description": "사용 가능한 경우 각 배포판 레이블에 OS 버전 추가" + }, + "showComplianceHero": { + "label": "준수 상태 표시", + "description": "최신 호스트의 백분율을 표시하는 준수 링 표시" + }, + "osDisplayMode": { + "label": "OS 표시 모드", + "description": "운영 체제 배포판 표시 방법 선택", + "option": { + "bars": "가로 막대", + "donut": "도넛 차트" + } + } + }, + "error": { + "internalServerError": "PatchMon 데이터를 가져오지 못했습니다" + } + }, + "bazarr": { + "name": "Bazarr", + "description": "Bazarr 인스턴스의 누락된 자막 및 상태 개요", + "episodes": "누락된 에피소드", + "movies": "누락된 영화", + "providers": "제공자 문제", + "status": "상태 문제", + "option": { + "showMissingEpisodes": { + "label": "누락된 에피소드 표시", + "description": "누락된 자막이 있는 에피소드 수 표시" + }, + "showMissingMovies": { + "label": "누락된 영화 표시", + "description": "누락된 자막이 있는 영화 수 표시" + }, + "showProviderIssues": { + "label": "제공자 문제 표시", + "description": "문제가 있는 자막 제공자 수 표시" + }, + "showHealthIssues": { + "label": "상태 문제 표시", + "description": "Bazarr 상태 문제 수 표시" + } + }, + "error": { + "internalServerError": "Bazarr 데이터를 가져오지 못했습니다" + } + }, + "mediaMissing": { + "name": "누락 및 대기 중인 미디어", + "description": "Radarr 및 Sonarr의 누락 및 대기 중인 영화와 에피소드 표시", + "option": { + "showMissing": { + "label": "누락된 항목 표시" + }, + "showQueued": { + "label": "대기 중인 항목 표시" + }, + "pageSize": { + "label": "페이지당 항목 수" + } + }, + "tab": { + "missing": "누락", + "queued": "대기 중" + }, + "type": { + "movie": "영화", + "episode": "에피소드" + }, + "empty": { + "missing": "누락된 항목 없음", + "queued": "대기 중인 항목 없음", + "noTabsEnabled": "위젯 설정에서 최소한 하나의 탭을 활성화하세요" + }, + "timeLeft": "남은 시간" + }, + "traefik": { + "name": "Traefik", + "description": "Traefik 라우터, 서비스, 미들웨어 및 진입점 개요", + "option": { + "showTcp": { + "label": "TCP 표시" + }, + "showUdp": { + "label": "UDP 표시" + }, + "showEntryPoints": { + "label": "진입점 표시" + } + }, + "instances": "Traefik 인스턴스", + "versionUnknown": "버전 알 수 없음", + "summary": { + "routers": "라우터", + "entryPoints": "진입점" + }, + "resource": { + "routers": "라우터", + "services": "서비스", + "middlewares": "미들웨어" + }, + "status": { + "healthy": "정상", + "errors": "{count}개 오류", + "warnings": "{count}개 경고" + }, + "error": { + "internalServerError": "Traefik 데이터를 가져오지 못함" + } } }, "widgetPreview": { @@ -4551,11 +4380,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "홈", "boards": "보드", "apps": "앱", "integrations": "통합", - "customWidgets": "사용자 지정 위젯", "searchEngies": "검색 엔진", "medias": "미디어", "users": { @@ -5694,6 +5523,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "관리", "boards": { "label": "보드" diff --git a/packages/translation/src/lang/lt.json b/packages/translation/src/lang/lt.json index efd19f523..62ff79725 100644 --- a/packages/translation/src/lang/lt.json +++ b/packages/translation/src/lang/lt.json @@ -688,211 +688,6 @@ "add": "" } }, - "customWidget": { - "page": { - "list": { - "title": "", - "noResults": "", - "loading": "" - }, - "create": { - "title": "", - "subtitle": "" - }, - "edit": { - "title": "" - } - }, - "action": { - "create": "", - "import": "", - "save": "", - "delete": "", - "deleteConfirm": "", - "export": "", - "addMapping": "", - "addColumn": "", - "edit": "", - "removeMapping": "", - "removeColumn": "", - "addItem": "", - "removeItem": "", - "addBar": "", - "duplicate": "", - "copyAiPrompt": "", - "enable": "", - "disable": "", - "menu": "" - }, - "field": { - "name": "", - "description": "", - "iconUrl": "", - "url": "", - "authType": "", - "headerName": "", - "method": "", - "requestBody": "", - "displayType": "", - "jsonPath": "", - "jsonPathHint": "", - "label": "", - "unit": "", - "mappings": "", - "tablePath": "", - "tablePathHint": "", - "columns": "", - "header": "", - "items": "", - "gridColumns": "", - "cardStyle": "", - "bars": "", - "valuePath": "", - "maxPath": "", - "showPercentage": "", - "barSize": "", - "goodValues": "", - "dotSize": "", - "valueSize": "", - "labelPosition": "", - "kvLayout": "", - "striped": "", - "compact": "", - "maxHeight": "", - "color": "", - "buttonLabel": "", - "buttonColor": "", - "confirmText": "", - "confirmTextHint": "", - "successMessage": "", - "successMessageHint": "", - "enabled": "", - "template": { - "label": "", - "description": "" - } - }, - "placeholder": { - "exampleLabel": "", - "exampleLabelShort": "", - "exampleHeader": "", - "exampleUnit": "", - "iconUrl": "", - "url": "", - "headerName": "", - "jsonPath": "", - "tablePath": "", - "columnJsonPath": "", - "valuePath": "", - "maxPath": "", - "goodValues": "", - "color": "" - }, - "cardStyleOption": { - "filled": "", - "outline": "", - "subtle": "" - }, - "layoutOption": { - "list": "", - "grid": "" - }, - "sizeOption": { - "sm": "", - "md": "", - "lg": "", - "xl": "" - }, - "labelPositionOption": { - "above": "", - "below": "" - }, - "fieldset": { - "general": "", - "connection": "", - "display": "" - }, - "displayTypeDescription": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "method": { - "GET": "", - "POST": "", - "PUT": "", - "DELETE": "", - "PATCH": "" - }, - "authType": { - "none": "", - "bearer": "", - "basic": "", - "apiKeyHeader": "", - "apiKeyQuery": "" - }, - "displayType": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "secret": { - "apiKey": "", - "username": "", - "password": "", - "savedPlaceholder": "" - }, - "preview": { - "title": "", - "test": "", - "hint": "", - "rawResponse": "" - }, - "notification": { - "created": "", - "updated": "", - "deleted": "", - "imported": "", - "aiPromptCopied": "", - "aiPromptDescription": "", - "aiPromptCopy": "", - "aiPromptNoResponse": "", - "aiPromptCopyError": "", - "createError": "", - "updateError": "", - "importError": "", - "exportError": "", - "duplicated": "", - "duplicateError": "", - "toggleError": "", - "deleteError": "", - "previewError": "", - "executed": "", - "executeError": "" - }, - "table": { - "name": "", - "url": "", - "display": "" - }, - "widget": { - "disabled": "" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "Nepavyko gauti Paperless-ngx duomenų" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "", "description": "", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "RSS srautai", "description": "Stebėti ir rodyti vieną ar daugiau bendrų RSS, ATOM arba JSON srautų", @@ -3744,40 +3323,6 @@ "internalServerError": "Nepavyko gauti veikimo duomenų" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "Garso statistika", "description": "Bibliotekos ir atkūrimo statistika iš Navidrome arba Audiobookshelf", @@ -3901,26 +3446,6 @@ "unhealthy": "" } }, - "customApi": { - "name": "", - "description": "", - "option": { - "definitionId": { - "label": "" - }, - "refreshInterval": { - "label": "", - "description": "" - } - }, - "noDefinition": "", - "definitionNotFound": "", - "noDisplayOutput": "", - "executeConfirm": "", - "executing": "", - "executeSuccess": "", - "executeFailed": "" - }, "beszelSystemTable": { "name": "Beszel sistemos (lentelė)", "description": "Visų Beszel stebimų sistemų lentelės vaizdas su rūšiuojamais stulpeliais ir būsenos indikatoriais", @@ -4171,6 +3696,256 @@ "subtitle": "Docker konteinerių tinklo srautas" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Pagrindinis", "boards": "Lentos", "apps": "Programėlės", "integrations": "Integracijos", - "customWidgets": "", "searchEngies": "Paieškos sistemos", "medias": "Medijos", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Valdyti", "boards": { "label": "Lentos" @@ -5728,18 +5506,6 @@ "label": "" } }, - "custom-widgets": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "", - "flow": { - "label": "" - } - } - }, "users": { "label": "Vartotojai", "create": { diff --git a/packages/translation/src/lang/lv.json b/packages/translation/src/lang/lv.json index 86cfc30b6..689d618a1 100644 --- a/packages/translation/src/lang/lv.json +++ b/packages/translation/src/lang/lv.json @@ -691,206 +691,11 @@ "customWidget": { "page": { "list": { - "title": "Pielāgotie logrīki", - "noResults": "Vēl nav pielāgotu logrīku. Izveidojiet pirmo!", "loading": "Notiek ielāde..." - }, - "create": { - "title": "Izveidot pielāgotu logrīku", - "subtitle": "Definējiet API URL, autentifikāciju un to, kā attēlot atbildes datus." - }, - "edit": { - "title": "Rediģēt pielāgoto logrīku" } }, "action": { - "create": "Izveidot", - "import": "Importēt", - "save": "Saglabāt", - "delete": "Dzēst pielāgoto logrīku", - "deleteConfirm": "Vai tiešām vēlaties dzēst \"{name}\"? Šo darbību nevar atsaukt.", - "export": "Eksportēt", - "addMapping": "Pievienot kartējumu", - "addColumn": "Pievienot kolonnu", - "edit": "Rediģēt", - "removeMapping": "Noņemt kartējumu", - "removeColumn": "Noņemt kolonnu", - "addItem": "", - "removeItem": "", - "addBar": "", - "duplicate": "", - "copyAiPrompt": "", - "enable": "", - "disable": "", - "menu": "" - }, - "field": { - "name": "", - "description": "", - "iconUrl": "", - "url": "", - "authType": "", - "headerName": "", - "method": "", - "requestBody": "", - "displayType": "", - "jsonPath": "", - "jsonPathHint": "", - "label": "", - "unit": "", - "mappings": "", - "tablePath": "", - "tablePathHint": "", - "columns": "", - "header": "", - "items": "", - "gridColumns": "", - "cardStyle": "", - "bars": "", - "valuePath": "", - "maxPath": "", - "showPercentage": "", - "barSize": "", - "goodValues": "", - "dotSize": "", - "valueSize": "", - "labelPosition": "", - "kvLayout": "", - "striped": "", - "compact": "", - "maxHeight": "", - "color": "", - "buttonLabel": "", - "buttonColor": "", - "confirmText": "", - "confirmTextHint": "", - "successMessage": "", - "successMessageHint": "", - "enabled": "", - "template": { - "label": "", - "description": "" - } - }, - "placeholder": { - "exampleLabel": "", - "exampleLabelShort": "", - "exampleHeader": "", - "exampleUnit": "", - "iconUrl": "", - "url": "", - "headerName": "", - "jsonPath": "", - "tablePath": "", - "columnJsonPath": "", - "valuePath": "", - "maxPath": "", - "goodValues": "", - "color": "" - }, - "cardStyleOption": { - "filled": "", - "outline": "", - "subtle": "" - }, - "layoutOption": { - "list": "", - "grid": "" - }, - "sizeOption": { - "sm": "", - "md": "", - "lg": "", - "xl": "" - }, - "labelPositionOption": { - "above": "", - "below": "" - }, - "fieldset": { - "general": "", - "connection": "", - "display": "" - }, - "displayTypeDescription": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "method": { - "GET": "", - "POST": "", - "PUT": "", - "DELETE": "", - "PATCH": "" - }, - "authType": { - "none": "", - "bearer": "", - "basic": "", - "apiKeyHeader": "", - "apiKeyQuery": "" - }, - "displayType": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "secret": { - "apiKey": "", - "username": "", - "password": "", - "savedPlaceholder": "" - }, - "preview": { - "title": "", - "test": "", - "hint": "", - "rawResponse": "" - }, - "notification": { - "created": "", - "updated": "", - "deleted": "", - "imported": "", - "aiPromptCopied": "", - "aiPromptDescription": "", - "aiPromptCopy": "", - "aiPromptNoResponse": "", - "aiPromptCopyError": "", - "createError": "", - "updateError": "", - "importError": "", - "exportError": "", - "duplicated": "", - "duplicateError": "", - "toggleError": "", - "deleteError": "", - "previewError": "", - "executed": "", - "executeError": "" - }, - "table": { - "name": "", - "url": "", - "display": "" - }, - "widget": { - "disabled": "" + "create": "Izveidot" } }, "integration": { @@ -2828,193 +2633,6 @@ "internalServerError": "Neizdevās iegūt Paperless-ngx datus" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "", "description": "", @@ -3387,35 +3005,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "", "description": "", @@ -3744,40 +3333,6 @@ "internalServerError": "Neizdevās iegūt pieejamības datus" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "Audio statistika", "description": "Bibliotēkas un atskaņošanas statistika no Navidrome vai Audiobookshelf", @@ -3901,26 +3456,6 @@ "unhealthy": "" } }, - "customApi": { - "name": "", - "description": "", - "option": { - "definitionId": { - "label": "" - }, - "refreshInterval": { - "label": "", - "description": "" - } - }, - "noDefinition": "", - "definitionNotFound": "", - "noDisplayOutput": "", - "executeConfirm": "", - "executing": "", - "executeSuccess": "", - "executeFailed": "" - }, "beszelSystemTable": { "name": "Beszel sistēmas (Tabula)", "description": "Tabulas skats visām Beszel uzraudzītajām sistēmām ar kārtojamām kolonnām un statusa indikatoriem", @@ -4171,6 +3706,256 @@ "subtitle": "Docker konteineru tīkla trafika" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4336,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Sākums", "boards": "Dēļi", "apps": "Lietotnes", "integrations": "", - "customWidgets": "", "searchEngies": "", "medias": "", "users": { @@ -5694,6 +5479,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Pārvaldīt", "boards": { "label": "Dēļi" @@ -5728,18 +5516,6 @@ "label": "Rediģēt" } }, - "custom-widgets": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "", - "flow": { - "label": "" - } - } - }, "users": { "label": "Lietotāji", "create": { diff --git a/packages/translation/src/lang/pt-br.json b/packages/translation/src/lang/pt-br.json index d96857250..a78191198 100644 --- a/packages/translation/src/lang/pt-br.json +++ b/packages/translation/src/lang/pt-br.json @@ -710,16 +710,8 @@ "delete": "Excluir widget personalizado", "deleteConfirm": "Tem certeza de que deseja excluir \"{name}\"? Esta ação não pode ser desfeita.", "export": "Exportar", - "addMapping": "Adicionar Mapeamento", - "addColumn": "Adicionar Coluna", "edit": "Editar", - "removeMapping": "Remover Mapeamento", - "removeColumn": "Remover coluna", - "addItem": "Adicionar Item", - "removeItem": "Remover item", - "addBar": "Adicionar barra", "duplicate": "Duplicar", - "copyAiPrompt": "Copiar prompt de IA", "enable": "Habilitado", "disable": "Desabilitado", "menu": "Ações" @@ -727,150 +719,13 @@ "field": { "name": "Nome", "description": "Descrição", - "iconUrl": "URL do ícone", - "url": "URL", - "authType": "Tipo de Autenticação", - "headerName": "Nome do parâmetro de cabeçalho/consulta", - "method": "Método", - "requestBody": "Corpo da requisição", - "displayType": "Tipo de exibição", - "jsonPath": "Caminho JSON", - "jsonPathHint": "Usar sintaxe JSONPath para extrair valores, por exemplo, $.data.temperature ou $.items[0].name", - "label": "Rótulo", - "unit": "Unidade", - "mappings": "Mapeamentos", - "tablePath": "Caminho Array JSON", - "tablePathHint": "Caminho para o array na resposta, por exemplo, $.data.items", - "columns": "Colunas", - "header": "Header (cabeçalho)", - "items": "Itens", - "gridColumns": "Colunas da grade", - "cardStyle": "Estilo de cartão", - "bars": "Barras", - "valuePath": "Caminho do valor JSON", - "maxPath": "Caminho do Max Valor JSON", - "showPercentage": "Mostrar porcentagem", - "barSize": "Tamanho da barra", - "goodValues": "Valores bons (separados por vírgula)", - "dotSize": "Tamanho do ponto", - "valueSize": "Tamanho do valor", - "labelPosition": "Posição do rótulo", - "kvLayout": "Layout", - "striped": "Linhas Listradas", - "compact": "Modo Compacto", - "maxHeight": "Altura máxima (px)", - "color": "Cor", - "buttonLabel": "Rótulo do botão", - "buttonColor": "Cor do botão", - "confirmText": "Texto de confirmação", - "confirmTextHint": "Se definido, um diálogo de confirmação irá aparecer antes de executar a solicitação", - "successMessage": "Mensagem de Sucesso", - "successMessageHint": "Mensagem mostrada após execução com sucesso", - "enabled": "Habilitado", - "template": { - "label": "Template JSX", - "description": "" - } - }, - "placeholder": { - "exampleLabel": "Temperatura da CPU", - "exampleLabelShort": "Temp CPU", - "exampleHeader": "Nome", - "exampleUnit": "°C", - "iconUrl": "https://...", - "url": "https://api.exemplo.com/br/api/v1/status", - "headerName": "X-API-Key", - "jsonPath": "$.data.value", - "tablePath": "$.data.items", - "columnJsonPath": "$.nome", - "valuePath": "$.data.used", - "maxPath": "$.data.total", - "goodValues": "online, true, up", - "color": "azul" - }, - "cardStyleOption": { - "filled": "Preenchido", - "outline": "Contorno", - "subtle": "Sutil" - }, - "layoutOption": { - "list": "Lista", - "grid": "Grade" - }, - "sizeOption": { - "sm": "Pequeno", - "md": "Médio", - "lg": "Grande", - "xl": "Extra grande" - }, - "labelPositionOption": { - "above": "Acima", - "below": "Abaixo" - }, - "fieldset": { - "general": "Geral", - "connection": "Conexão com API", - "display": "Configurações de tela" - }, - "displayTypeDescription": { - "singleValue": "Exibir um valor extraído com rótulo e unidade", - "keyValue": "Exibir vários valores rotulados lado a lado", - "table": "Exibir linhas de dados em formato de tabela", - "statGrid": "Estatísticas coloridas em uma grade — como Pi-Hole ou Widgets Rápidos", - "progressBars": "Barras de progresso mostrando uso ou conclusão — para disco, memória, quotas", - "statusIndicator": "Pontos de status coloridos mostrando estados online/offline ou de saúde", - "countGrid": "Contadores compactos de número + rótulo em uma grade apertada", - "raw": "Saída JSON impressa para depuração", - "actionButton": "Um botão que aciona uma solicitação quando clicado", - "customJsx": "Layout JSX personalizado usando componentes Mantine na lista branca com ligação completa de dados de API" - }, - "method": { - "GET": "GET", - "POST": "POST", - "PUT": "PUT", - "DELETE": "DELETE", - "PATCH": "PATCH" - }, - "authType": { - "none": "Nenhum", - "bearer": "Token Bearer", - "basic": "Autenticação Básica", - "apiKeyHeader": "Chave API (Cabeçalho)", - "apiKeyQuery": "Chave API (Consulta)" - }, - "displayType": { - "singleValue": "Valor Único", - "keyValue": "Chave-Valor", - "table": "Tabela", - "statGrid": "Grade de Estatísticas", - "progressBars": "Barras de Progresso", - "statusIndicator": "Indicador de Status", - "countGrid": "Grade de Contagem", - "raw": "JSON Bruto", - "actionButton": "Botão de Ação", - "customJsx": "JSX personalizado" - }, - "secret": { - "apiKey": "Chave de API / Token", - "username": "Usuário", - "password": "Senha", - "savedPlaceholder": "••••••• (salvo, deixe em branco para manter)" - }, - "preview": { - "title": "Pré-visualizar", - "test": "Testar", - "hint": "Clique em Testar para visualizar a resposta da API com sua configuração atual.", - "rawResponse": "Resposta JSON Bruta" + "iconUrl": "URL do ícone" }, "notification": { "created": "Widget \"{name}\" criado com sucesso.", "updated": "Widget \"{name}atualizado com sucesso.", "deleted": "Widget \"{name}excluído.", "imported": "Widget importado com sucesso.", - "aiPromptCopied": "Prompt de IA copiado para a área de transferência", - "aiPromptDescription": "Copie um prompt pré-construído para colar qualquer chatbot de AI (ChatGPT, Claude, Gemini...). Ele inclui o esquema completo de widget e a sua resposta de API para que a AI possa gerar uma configuração JSON pronta para importar para você.", - "aiPromptCopy": "Copiar para área de transferência", - "aiPromptNoResponse": "Dica: Execute um teste primeiro para incluir a sua API de resposta no prompt para melhores resultados.", "aiPromptCopyError": "Falha ao copiar prompt para área de transferência. O seu navegador pode não suportar este recurso.", "createError": "Falha ao criar widget. Verifique se o endpoint API está acessível.", "updateError": "Falha ao atualizar o widget. Suas alterações não foram salvas.", @@ -883,14 +738,6 @@ "previewError": "Falha ao buscar a pré-visualização. Verifique a URL e tente novamente.", "executed": "Ação executada com sucesso.", "executeError": "A ação falhou: {error}" - }, - "table": { - "name": "Nome", - "url": "URL", - "display": "Exibição" - }, - "widget": { - "disabled": "Este widget está desabilitado" } }, "integration": { @@ -2828,193 +2675,6 @@ "internalServerError": "Falha ao buscar dados do Paperless-ngx" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "Estatísticas do Servidor Immich", "description": "Informações sobre sua instância do Immich", @@ -3387,35 +3047,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "Feeds RSS", "description": "Monitora e exibe um ou mais feeds RSS, ATOM ou JSON genéricos", @@ -3744,40 +3375,6 @@ "internalServerError": "Falha ao buscar dados de tempo de atividade" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "Estatísticas de áudio", "description": "Estatísticas de biblioteca e reprodução do Navidrome ou Audiobookshelf", @@ -3901,26 +3498,6 @@ "unhealthy": "Não saudável" } }, - "customApi": { - "name": "API personalizada", - "description": "Exibir dados de qualquer API externa com configuração personalizada.", - "option": { - "definitionId": { - "label": "ID de definição" - }, - "refreshInterval": { - "label": "Intervalo de atualização", - "description": "Com que frequência reobter dados da API (em segundos)" - } - }, - "noDefinition": "Nenhuma definição selecionada", - "definitionNotFound": "Definição do widget não encontrada. Ela pode ter sido excluída.", - "noDisplayOutput": "Nenhuma saída de exibição", - "executeConfirm": "Tem certeza de que deseja executar esta ação?", - "executing": "Executando...", - "executeSuccess": "Ação executada com sucesso", - "executeFailed": "Ação falhou. Verifique a configuração do widget." - }, "beszelSystemTable": { "name": "Sistemas Beszel (Tabela)", "description": "Visualização em tabela de todos os sistemas monitorados pelo Beszel com colunas classificáveis e indicadores de status", @@ -4171,6 +3748,256 @@ "subtitle": "Tráfego de rede dos contêineres Docker" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4378,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Início", "boards": "Placas", "apps": "Aplicativos", "integrations": "Integrações", - "customWidgets": "Widgets Personalizados", "searchEngies": "Mecanismos de busca", "medias": "Mídias", "users": { @@ -5694,6 +5521,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Gerenciar", "boards": { "label": "Placas" @@ -5728,18 +5558,6 @@ "label": "Editar" } }, - "custom-widgets": { - "label": "Widgets personalizados", - "new": { - "label": "Novo" - }, - "edit": { - "label": "Editar", - "flow": { - "label": "Fluxo" - } - } - }, "users": { "label": "Usuários", "create": { diff --git a/packages/translation/src/lang/pt.json b/packages/translation/src/lang/pt.json index 580ba60b3..3367bad51 100644 --- a/packages/translation/src/lang/pt.json +++ b/packages/translation/src/lang/pt.json @@ -688,211 +688,6 @@ "add": "" } }, - "customWidget": { - "page": { - "list": { - "title": "", - "noResults": "", - "loading": "" - }, - "create": { - "title": "", - "subtitle": "" - }, - "edit": { - "title": "" - } - }, - "action": { - "create": "", - "import": "", - "save": "", - "delete": "", - "deleteConfirm": "", - "export": "", - "addMapping": "", - "addColumn": "", - "edit": "", - "removeMapping": "", - "removeColumn": "", - "addItem": "", - "removeItem": "", - "addBar": "", - "duplicate": "", - "copyAiPrompt": "", - "enable": "", - "disable": "", - "menu": "" - }, - "field": { - "name": "", - "description": "", - "iconUrl": "", - "url": "", - "authType": "", - "headerName": "", - "method": "", - "requestBody": "", - "displayType": "", - "jsonPath": "", - "jsonPathHint": "", - "label": "", - "unit": "", - "mappings": "", - "tablePath": "", - "tablePathHint": "", - "columns": "", - "header": "", - "items": "", - "gridColumns": "", - "cardStyle": "", - "bars": "", - "valuePath": "", - "maxPath": "", - "showPercentage": "", - "barSize": "", - "goodValues": "", - "dotSize": "", - "valueSize": "", - "labelPosition": "", - "kvLayout": "", - "striped": "", - "compact": "", - "maxHeight": "", - "color": "", - "buttonLabel": "", - "buttonColor": "", - "confirmText": "", - "confirmTextHint": "", - "successMessage": "", - "successMessageHint": "", - "enabled": "", - "template": { - "label": "", - "description": "" - } - }, - "placeholder": { - "exampleLabel": "", - "exampleLabelShort": "", - "exampleHeader": "", - "exampleUnit": "", - "iconUrl": "", - "url": "", - "headerName": "", - "jsonPath": "", - "tablePath": "", - "columnJsonPath": "", - "valuePath": "", - "maxPath": "", - "goodValues": "", - "color": "" - }, - "cardStyleOption": { - "filled": "", - "outline": "", - "subtle": "" - }, - "layoutOption": { - "list": "", - "grid": "" - }, - "sizeOption": { - "sm": "", - "md": "", - "lg": "", - "xl": "" - }, - "labelPositionOption": { - "above": "", - "below": "" - }, - "fieldset": { - "general": "", - "connection": "", - "display": "" - }, - "displayTypeDescription": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "method": { - "GET": "", - "POST": "", - "PUT": "", - "DELETE": "", - "PATCH": "" - }, - "authType": { - "none": "", - "bearer": "", - "basic": "", - "apiKeyHeader": "", - "apiKeyQuery": "" - }, - "displayType": { - "singleValue": "", - "keyValue": "", - "table": "", - "statGrid": "", - "progressBars": "", - "statusIndicator": "", - "countGrid": "", - "raw": "", - "actionButton": "", - "customJsx": "" - }, - "secret": { - "apiKey": "", - "username": "", - "password": "", - "savedPlaceholder": "" - }, - "preview": { - "title": "", - "test": "", - "hint": "", - "rawResponse": "" - }, - "notification": { - "created": "", - "updated": "", - "deleted": "", - "imported": "", - "aiPromptCopied": "", - "aiPromptDescription": "", - "aiPromptCopy": "", - "aiPromptNoResponse": "", - "aiPromptCopyError": "", - "createError": "", - "updateError": "", - "importError": "", - "exportError": "", - "duplicated": "", - "duplicateError": "", - "toggleError": "", - "deleteError": "", - "previewError": "", - "executed": "", - "executeError": "" - }, - "table": { - "name": "", - "url": "", - "display": "" - }, - "widget": { - "disabled": "" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "", "description": "", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "Feeds RSS", "description": "Monitora e exibe um ou mais feeds RSS, ATOM ou JSON genéricos", @@ -3744,40 +3323,6 @@ "internalServerError": "" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "", "description": "", @@ -3901,26 +3446,6 @@ "unhealthy": "" } }, - "customApi": { - "name": "", - "description": "", - "option": { - "definitionId": { - "label": "" - }, - "refreshInterval": { - "label": "", - "description": "" - } - }, - "noDefinition": "", - "definitionNotFound": "", - "noDisplayOutput": "", - "executeConfirm": "", - "executing": "", - "executeSuccess": "", - "executeFailed": "" - }, "beszelSystemTable": { "name": "Sistemas Beszel (Tabela)", "description": "Visualização em tabela de todos os sistemas monitorados pelo Beszel com colunas classificáveis e indicadores de status", @@ -4171,6 +3696,256 @@ "subtitle": "Tráfego de rede dos contêineres Docker" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Início", "boards": "Painéis", "apps": "Aplicativos", "integrations": "Integrações", - "customWidgets": "", "searchEngies": "Mecanismos de busca", "medias": "Mídias", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Gerenciar", "boards": { "label": "Painéis" @@ -5728,18 +5506,6 @@ "label": "Editar" } }, - "custom-widgets": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "", - "flow": { - "label": "" - } - } - }, "users": { "label": "Usuários", "create": { diff --git a/packages/translation/src/lang/sk.json b/packages/translation/src/lang/sk.json index c19915673..a84511aa7 100644 --- a/packages/translation/src/lang/sk.json +++ b/packages/translation/src/lang/sk.json @@ -688,211 +688,6 @@ "add": "Pridajte aplikáciu" } }, - "customWidget": { - "page": { - "list": { - "title": "Vlastné widgety", - "noResults": "Zatiaľ žiadne vlastné widgety. Vytvorte svoj prvý!", - "loading": "Nahrávam..." - }, - "create": { - "title": "Vytvoriť vlastný widget", - "subtitle": "Definujte URL API, autentifikáciu a spôsob zobrazenia údajov odpovede." - }, - "edit": { - "title": "Upraviť vlastný widget" - } - }, - "action": { - "create": "Vytvoriť", - "import": "Importovať", - "save": "Uložiť", - "delete": "Odstrániť vlastný widget", - "deleteConfirm": "Naozaj chcete odstrániť \"{name}\"? Táto akcia sa nedá vrátiť späť.", - "export": "Exportovať", - "addMapping": "Pridať mapovanie", - "addColumn": "Pridať stĺpec", - "edit": "Upraviť", - "removeMapping": "Odstrániť mapovanie", - "removeColumn": "Odstrániť stĺpec", - "addItem": "Pridať položku", - "removeItem": "Odstrániť položku", - "addBar": "Pridať pruh", - "duplicate": "Duplikovať", - "copyAiPrompt": "Kopírovať AI prompt", - "enable": "Povoliť", - "disable": "Zakázať", - "menu": "Akcie" - }, - "field": { - "name": "Názov", - "description": "Popis", - "iconUrl": "URL ikony", - "url": "URL", - "authType": "Typ autentifikácie", - "headerName": "Názov hlavičky/parametra dotazu", - "method": "Metóda", - "requestBody": "Telo požiadavky", - "displayType": "Typ zobrazenia", - "jsonPath": "JSON cesta", - "jsonPathHint": "Použite syntax JSONPath na extrakciu hodnôt, napr. $.data.teplota alebo $.polozky[0].nazov", - "label": "Označenie", - "unit": "Jednotka", - "mappings": "Mapovania", - "tablePath": "JSON cesta poľa", - "tablePathHint": "Cesta k poľu v odpovedi, napr. $.data.polozky", - "columns": "Stĺpce", - "header": "Hlavička", - "items": "Položky", - "gridColumns": "Stĺpce mriežky", - "cardStyle": "Štýl karty", - "bars": "Pruhy", - "valuePath": "JSON cesta hodnoty", - "maxPath": "JSON cesta maximálnej hodnoty", - "showPercentage": "Zobraziť percentá", - "barSize": "Veľkosť pruhu", - "goodValues": "Dobré hodnoty (oddelené čiarkou)", - "dotSize": "Veľkosť bodky", - "valueSize": "Veľkosť hodnoty", - "labelPosition": "Pozícia označenia", - "kvLayout": "Rozloženie", - "striped": "Pruhované riadky", - "compact": "Kompaktný režim", - "maxHeight": "Max. výška (px)", - "color": "Farba", - "buttonLabel": "Označenie tlačidla", - "buttonColor": "Farba tlačidla", - "confirmText": "Text potvrdenia", - "confirmTextHint": "Ak je nastavený, pred vykonaním požiadavky sa zobrazí dialóg potvrdenia", - "successMessage": "Správa o úspechu", - "successMessageHint": "Správa zobrazená po úspešnom vykonaní", - "enabled": "Povolené", - "template": { - "label": "JSX šablóna", - "description": "Mantine JSX šablóna. Prístup k poliam odpovede API cez dátové väzby (napr. data.nazov). Používajte iba whitelistované komponenty. Zakázané: constructor, __proto__, eval, Function, window, document." - } - }, - "placeholder": { - "exampleLabel": "Teplota CPU", - "exampleLabelShort": "Teplota CPU", - "exampleHeader": "Názov", - "exampleUnit": "°C", - "iconUrl": "https://...", - "url": "https://api.priklad.com/api/v1/status", - "headerName": "X-API-Key", - "jsonPath": "$.data.hodnota", - "tablePath": "$.data.polozky", - "columnJsonPath": "$.nazov", - "valuePath": "$.data.pouzite", - "maxPath": "$.data.celkom", - "goodValues": "online, true, up", - "color": "modrá" - }, - "cardStyleOption": { - "filled": "Vyplnené", - "outline": "Obrys", - "subtle": "Jemný" - }, - "layoutOption": { - "list": "Zoznam", - "grid": "Mriežka" - }, - "sizeOption": { - "sm": "Malé", - "md": "Stredné", - "lg": "Veľké", - "xl": "Extra veľké" - }, - "labelPositionOption": { - "above": "Nad", - "below": "Pod" - }, - "fieldset": { - "general": "Všeobecné", - "connection": "Pripojenie API", - "display": "Konfigurácia zobrazenia" - }, - "displayTypeDescription": { - "singleValue": "Zobraziť jednu extrahovanú hodnotu s označením a jednotkou", - "keyValue": "Zobraziť viacero označených hodnôt vedľa seba", - "table": "Zobraziť riadky údajov vo formáte tabuľky", - "statGrid": "Farebné karty štatistík v mriežke – ako widgety Pi-Hole alebo Speedtest", - "progressBars": "Pruhy postupu zobrazujúce využitie alebo dokončenie – pre disk, pamäť, kvóty", - "statusIndicator": "Farebné bodky stavu zobrazujúce online/offline alebo stavy zdravia", - "countGrid": "Kompaktné počítadlá číslo + označenie v tesnej mriežke", - "raw": "Prehľadne formátovaný JSON výstup pre ladenie", - "actionButton": "Tlačidlo, ktoré po kliknutí spustí požiadavku", - "customJsx": "Vlastné rozloženie JSX pomocou whitelistovaných komponentov Mantine s plnou väzbou API dát" - }, - "method": { - "GET": "GET", - "POST": "POST", - "PUT": "PUT", - "DELETE": "DELETE", - "PATCH": "PATCH" - }, - "authType": { - "none": "Žiadna", - "bearer": "Bearer token", - "basic": "Basic Auth", - "apiKeyHeader": "API kľúč (hlavička)", - "apiKeyQuery": "API kľúč (dotaz)" - }, - "displayType": { - "singleValue": "Jedna hodnota", - "keyValue": "Kľúč-hodnota", - "table": "Tabuľka", - "statGrid": "Mriežka štatistík", - "progressBars": "Pruhy postupu", - "statusIndicator": "Indikátor stavu", - "countGrid": "Mriežka počtu", - "raw": "Surové JSON", - "actionButton": "Akčné tlačidlo", - "customJsx": "Vlastné JSX" - }, - "secret": { - "apiKey": "API kľúč / token", - "username": "Používateľské meno", - "password": "Heslo", - "savedPlaceholder": "••••••• (uložené, ponechajte prázdne pre zachovanie)" - }, - "preview": { - "title": "Náhľad", - "test": "Test", - "hint": "Kliknite na Test pre náhľad odpovede API s vašou aktuálnou konfiguráciou.", - "rawResponse": "Surová JSON odpoveď" - }, - "notification": { - "created": "Widget \"{name}\" bol úspešne vytvorený.", - "updated": "Widget \"{name}\" bol úspešne aktualizovaný.", - "deleted": "Widget \"{name}\" bol odstránený.", - "imported": "", - "aiPromptCopied": "AI prompt skopírovaný do schránky", - "aiPromptDescription": "Skopírujte pripravený prompt a vložte ho do akéhokoľvek AI chatbota (ChatGPT, Claude, Gemini...). Obsahuje úplnú schému widgetu a vašu odpoveď API, aby AI mohla vygenerovať pripravenú JSON konfiguráciu na import.", - "aiPromptCopy": "Skopírovať do schránky", - "aiPromptNoResponse": "Tip: Najprv spustite test, aby ste zahrnuli odpoveď API do výzvy pre lepšie výsledky.", - "aiPromptCopyError": "Nepodarilo sa skopírovať výzvu do schránky. Váš prehliadač možno nepodporuje túto funkciu.", - "createError": "Nepodarilo sa vytvoriť widget. Skontrolujte, či je váš API endpoint dostupný.", - "updateError": "Nepodarilo sa aktualizovať widget. Vaše zmeny neboli uložené.", - "importError": "Nepodarilo sa importovať widget. Uistite sa, že súbor je platný JSON export vlastného widgetu.", - "exportError": "", - "duplicated": "", - "duplicateError": "", - "toggleError": "", - "deleteError": "", - "previewError": "", - "executed": "", - "executeError": "" - }, - "table": { - "name": "", - "url": "", - "display": "" - }, - "widget": { - "disabled": "" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "Nepodarilo sa načítať údaje Paperless-ngx" } }, - "patchmon": { - "name": "", - "description": "", - "title": "", - "totalHosts": "", - "hostsNeedingUpdates": "", - "securityUpdates": "", - "upToDateHosts": "", - "hostsWithSecurityUpdates": "", - "recentUpdates24h": "", - "totalOutdatedPackages": "", - "totalRepos": "", - "osDistribution": "", - "compliance": "", - "complianceRatio": "", - "lastUpdated": "", - "option": { - "showTotalHosts": { - "label": "", - "description": "" - }, - "showHostsNeedingUpdates": { - "label": "", - "description": "" - }, - "showSecurityUpdates": { - "label": "", - "description": "" - }, - "showUpToDateHosts": { - "label": "", - "description": "" - }, - "showHostsWithSecurityUpdates": { - "label": "", - "description": "" - }, - "showRecentUpdates24h": { - "label": "", - "description": "" - }, - "showTotalOutdatedPackages": { - "label": "", - "description": "" - }, - "showTotalRepos": { - "label": "", - "description": "" - }, - "enableThresholdColors": { - "label": "", - "description": "" - }, - "useCustomThresholds": { - "label": "", - "description": "" - }, - "thresholdMode": { - "option": { - "absolute": "", - "percent": "" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "securityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "securityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "securityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "", - "description": "" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "", - "description": "" - }, - "upToDateHostsThresholdMode": { - "label": "", - "description": "" - }, - "upToDateHostsWarningAt": { - "label": "", - "description": "" - }, - "upToDateHostsCriticalAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesWarningAt": { - "label": "", - "description": "" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "", - "description": "" - }, - "showOsDistribution": { - "label": "", - "description": "" - }, - "osDistributionLimit": { - "label": "", - "description": "", - "option": { - "3": "", - "5": "", - "10": "", - "all": "" - } - }, - "showOsVersion": { - "label": "", - "description": "" - }, - "showComplianceHero": { - "label": "", - "description": "" - }, - "osDisplayMode": { - "label": "", - "description": "", - "option": { - "bars": "", - "donut": "" - } - } - }, - "error": { - "internalServerError": "" - } - }, - "bazarr": { - "name": "", - "description": "", - "episodes": "", - "movies": "", - "providers": "", - "status": "", - "option": { - "showMissingEpisodes": { - "label": "", - "description": "" - }, - "showMissingMovies": { - "label": "", - "description": "" - }, - "showProviderIssues": { - "label": "", - "description": "" - }, - "showHealthIssues": { - "label": "", - "description": "" - } - }, - "error": { - "internalServerError": "" - } - }, "immich-serverStats": { "name": "", "description": "", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "", - "description": "", - "option": { - "showMissing": { - "label": "" - }, - "showQueued": { - "label": "" - }, - "pageSize": { - "label": "" - } - }, - "tab": { - "missing": "", - "queued": "" - }, - "type": { - "movie": "", - "episode": "" - }, - "empty": { - "missing": "", - "queued": "", - "noTabsEnabled": "" - }, - "timeLeft": "" - }, "rssFeed": { "name": "RSS kanály", "description": "Monitorujte a zobrazujte jeden alebo viac všeobecných informačných kanálov RSS, ATOM alebo JSON", @@ -3744,40 +3323,6 @@ "internalServerError": "Nepodarilo sa načítať údaje o dostupnosti" } }, - "traefik": { - "name": "", - "description": "", - "option": { - "showTcp": { - "label": "" - }, - "showUdp": { - "label": "" - }, - "showEntryPoints": { - "label": "" - } - }, - "instances": "", - "versionUnknown": "", - "summary": { - "routers": "", - "entryPoints": "" - }, - "resource": { - "routers": "", - "services": "", - "middlewares": "" - }, - "status": { - "healthy": "", - "errors": "", - "warnings": "" - }, - "error": { - "internalServerError": "" - } - }, "audioStats": { "name": "Audio štatistiky", "description": "Štatistiky knižnice a prehrávania z Navidrome alebo Audiobookshelf", @@ -3901,26 +3446,6 @@ "unhealthy": "" } }, - "customApi": { - "name": "", - "description": "", - "option": { - "definitionId": { - "label": "" - }, - "refreshInterval": { - "label": "", - "description": "" - } - }, - "noDefinition": "", - "definitionNotFound": "", - "noDisplayOutput": "", - "executeConfirm": "", - "executing": "", - "executeSuccess": "", - "executeFailed": "" - }, "beszelSystemTable": { "name": "Beszel systémy (tabuľka)", "description": "Tabuľkový pohľad všetkých systémov monitorovaných Beszel s triediteľnými stĺpcami a indikátormi stavu", @@ -4171,6 +3696,256 @@ "subtitle": "Sieťová prevádzka Docker kontajnerov" } } + }, + "patchmon": { + "name": "", + "description": "", + "title": "", + "totalHosts": "", + "hostsNeedingUpdates": "", + "securityUpdates": "", + "upToDateHosts": "", + "hostsWithSecurityUpdates": "", + "recentUpdates24h": "", + "totalOutdatedPackages": "", + "totalRepos": "", + "osDistribution": "", + "compliance": "", + "complianceRatio": "", + "lastUpdated": "", + "option": { + "showTotalHosts": { + "label": "", + "description": "" + }, + "showHostsNeedingUpdates": { + "label": "", + "description": "" + }, + "showSecurityUpdates": { + "label": "", + "description": "" + }, + "showUpToDateHosts": { + "label": "", + "description": "" + }, + "showHostsWithSecurityUpdates": { + "label": "", + "description": "" + }, + "showRecentUpdates24h": { + "label": "", + "description": "" + }, + "showTotalOutdatedPackages": { + "label": "", + "description": "" + }, + "showTotalRepos": { + "label": "", + "description": "" + }, + "enableThresholdColors": { + "label": "", + "description": "" + }, + "useCustomThresholds": { + "label": "", + "description": "" + }, + "thresholdMode": { + "option": { + "absolute": "", + "percent": "" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "securityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "securityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "securityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "", + "description": "" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "", + "description": "" + }, + "upToDateHostsThresholdMode": { + "label": "", + "description": "" + }, + "upToDateHostsWarningAt": { + "label": "", + "description": "" + }, + "upToDateHostsCriticalAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesWarningAt": { + "label": "", + "description": "" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "", + "description": "" + }, + "showOsDistribution": { + "label": "", + "description": "" + }, + "osDistributionLimit": { + "label": "", + "description": "", + "option": { + "3": "", + "5": "", + "10": "", + "all": "" + } + }, + "showOsVersion": { + "label": "", + "description": "" + }, + "showComplianceHero": { + "label": "", + "description": "" + }, + "osDisplayMode": { + "label": "", + "description": "", + "option": { + "bars": "", + "donut": "" + } + } + }, + "error": { + "internalServerError": "" + } + }, + "bazarr": { + "name": "", + "description": "", + "episodes": "", + "movies": "", + "providers": "", + "status": "", + "option": { + "showMissingEpisodes": { + "label": "", + "description": "" + }, + "showMissingMovies": { + "label": "", + "description": "" + }, + "showProviderIssues": { + "label": "", + "description": "" + }, + "showHealthIssues": { + "label": "", + "description": "" + } + }, + "error": { + "internalServerError": "" + } + }, + "mediaMissing": { + "name": "", + "description": "", + "option": { + "showMissing": { + "label": "" + }, + "showQueued": { + "label": "" + }, + "pageSize": { + "label": "" + } + }, + "tab": { + "missing": "", + "queued": "" + }, + "type": { + "movie": "", + "episode": "" + }, + "empty": { + "missing": "", + "queued": "", + "noTabsEnabled": "" + }, + "timeLeft": "" + }, + "traefik": { + "name": "", + "description": "", + "option": { + "showTcp": { + "label": "" + }, + "showUdp": { + "label": "" + }, + "showEntryPoints": { + "label": "" + } + }, + "instances": "", + "versionUnknown": "", + "summary": { + "routers": "", + "entryPoints": "" + }, + "resource": { + "routers": "", + "services": "", + "middlewares": "" + }, + "status": { + "healthy": "", + "errors": "", + "warnings": "" + }, + "error": { + "internalServerError": "" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Domovská stránka", "boards": "Dosky", "apps": "Aplikácie", "integrations": "Integrácie", - "customWidgets": "", "searchEngies": "Vyhľadávače", "medias": "Médiá", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Spravovať", "boards": { "label": "Dosky" @@ -5728,18 +5506,6 @@ "label": "Upraviť" } }, - "custom-widgets": { - "label": "", - "new": { - "label": "" - }, - "edit": { - "label": "", - "flow": { - "label": "" - } - } - }, "users": { "label": "Používatelia", "create": { diff --git a/packages/translation/src/lang/tr.json b/packages/translation/src/lang/tr.json index 46296c573..b15519f95 100644 --- a/packages/translation/src/lang/tr.json +++ b/packages/translation/src/lang/tr.json @@ -688,211 +688,6 @@ "add": "Bir uygulama ekle" } }, - "customWidget": { - "page": { - "list": { - "title": "Özel Widget'lar", - "noResults": "Henüz özel widget yok. İlk widget'ınızı oluşturun!", - "loading": "Yükleniyor..." - }, - "create": { - "title": "Özel Widget Oluştur", - "subtitle": "API URL'sini, kimlik doğrulamasını ve yanıt verilerinin nasıl görüntüleneceğini tanımlayın." - }, - "edit": { - "title": "Özel Widget'ı Düzenle" - } - }, - "action": { - "create": "Oluştur", - "import": "İçe aktar", - "save": "Kaydet", - "delete": "Özel Widget'ı Sil", - "deleteConfirm": "“{name}” adlı widget'ı silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.", - "export": "Dışa aktar", - "addMapping": "Eşleme Ekle", - "addColumn": "Sütun Ekle", - "edit": "Düzenle", - "removeMapping": "Eşlemeyi kaldır", - "removeColumn": "Sütunu kaldır", - "addItem": "Öğe Ekle", - "removeItem": "Öğeyi kaldır", - "addBar": "Çubuk Ekle", - "duplicate": "Çoğalt", - "copyAiPrompt": "Yapay zekâ istemini kopyala", - "enable": "Etkinleştir", - "disable": "Devre dışı bırak", - "menu": "Eylemler" - }, - "field": { - "name": "Ad", - "description": "Açıklama", - "iconUrl": "Simge URL'si", - "url": "URL", - "authType": "Kimlik Doğrulama Türü", - "headerName": "Üst Bilgi/Sorgu Parametresi Adı", - "method": "Yöntem", - "requestBody": "İstek Gövdesi", - "displayType": "Görüntüleme Türü", - "jsonPath": "JSON Yolu", - "jsonPathHint": "Değerleri ayıklamak için JSONPath söz dizimini kullanın; ör. $.data.temperature veya $.items[0].name", - "label": "Etiket", - "unit": "Birim", - "mappings": "Eşlemeler", - "tablePath": "Dizi JSON Yolu", - "tablePathHint": "Yanıttaki dizinin yolu; ör. $.data.items", - "columns": "Sütunlar", - "header": "Başlık", - "items": "Öğeler", - "gridColumns": "Izgara Sütunları", - "cardStyle": "Kart Stili", - "bars": "Çubuklar", - "valuePath": "Değer JSON Yolu", - "maxPath": "En Yüksek Değer JSON Yolu", - "showPercentage": "Yüzdeyi Göster", - "barSize": "Çubuk Boyutu", - "goodValues": "İyi Değerler (virgülle ayrılmış)", - "dotSize": "Nokta Boyutu", - "valueSize": "Değer Boyutu", - "labelPosition": "Etiket Konumu", - "kvLayout": "Düzen", - "striped": "Şeritli Satırlar", - "compact": "Kompakt Mod", - "maxHeight": "En Fazla Yükseklik (px)", - "color": "Renk", - "buttonLabel": "Düğme Etiketi", - "buttonColor": "Düğme Rengi", - "confirmText": "Onay Metni", - "confirmTextHint": "Ayarlanırsa istek yürütülmeden önce bir onay iletişim kutusu gösterilir", - "successMessage": "Başarı Mesajı", - "successMessageHint": "Başarılı yürütmeden sonra gösterilecek mesaj", - "enabled": "Etkin", - "template": { - "label": "JSX Şablonu", - "description": "Mantine JSX şablonu. API yanıt alanlarına veri bağlamalarıyla (ör. data.name) erişin. Yalnızca izin verilen bileşenleri kullanın. Yasak: constructor, __proto__, eval, Function, window, document." - } - }, - "placeholder": { - "exampleLabel": "CPU Sıcaklığı", - "exampleLabelShort": "CPU Sıcaklığı", - "exampleHeader": "Ad", - "exampleUnit": "°C", - "iconUrl": "https://...", - "url": "https://api.example.com/api/v1/status", - "headerName": "X-API-Key", - "jsonPath": "$.data.value", - "tablePath": "$.data.items", - "columnJsonPath": "$.name", - "valuePath": "$.data.used", - "maxPath": "$.data.total", - "goodValues": "online, true, up", - "color": "mavi" - }, - "cardStyleOption": { - "filled": "Dolu", - "outline": "Çerçeveli", - "subtle": "Hafif" - }, - "layoutOption": { - "list": "Liste", - "grid": "Izgara" - }, - "sizeOption": { - "sm": "Küçük", - "md": "Orta", - "lg": "Büyük", - "xl": "Çok Büyük" - }, - "labelPositionOption": { - "above": "Üstte", - "below": "Altta" - }, - "fieldset": { - "general": "Genel", - "connection": "API Bağlantısı", - "display": "Görüntüleme Yapılandırması" - }, - "displayTypeDescription": { - "singleValue": "Ayıklanan tek bir değeri etiket ve birimle gösterir", - "keyValue": "Birden fazla etiketli değeri yan yana gösterir", - "table": "Veri satırlarını tablo biçiminde gösterir", - "statGrid": "Pi-hole veya Speedtest widget'ları gibi, ızgara içinde renkli istatistik kartları gösterir", - "progressBars": "Disk, bellek veya kotalar için kullanımı ya da tamamlanmayı gösteren ilerleme çubukları", - "statusIndicator": "Çevrimiçi/çevrimdışı ya da sağlık durumlarını gösteren renkli durum noktaları", - "countGrid": "Sıkı bir ızgarada kompakt sayı ve etiket sayaçları", - "raw": "Hata ayıklama için okunaklı biçimlendirilmiş JSON çıktısı", - "actionButton": "Tıklandığında istek başlatan bir düğme", - "customJsx": "Tam API veri bağlamasıyla izin verilen Mantine bileşenlerini kullanan özel JSX düzeni" - }, - "method": { - "GET": "GET", - "POST": "POST", - "PUT": "PUT", - "DELETE": "DELETE", - "PATCH": "PATCH" - }, - "authType": { - "none": "Yok", - "bearer": "Bearer Token", - "basic": "Temel Kimlik Doğrulama", - "apiKeyHeader": "API Anahtarı (Üst Bilgi)", - "apiKeyQuery": "API Anahtarı (Sorgu)" - }, - "displayType": { - "singleValue": "Tek Değer", - "keyValue": "Anahtar-Değer", - "table": "Tablo", - "statGrid": "İstatistik Izgarası", - "progressBars": "İlerleme Çubukları", - "statusIndicator": "Durum Göstergesi", - "countGrid": "Sayaç Izgarası", - "raw": "Ham JSON", - "actionButton": "Eylem Düğmesi", - "customJsx": "Özel JSX" - }, - "secret": { - "apiKey": "API Anahtarı / Token", - "username": "Kullanıcı adı", - "password": "Parola", - "savedPlaceholder": "••••••• (kaydedildi, korumak için boş bırakın)" - }, - "preview": { - "title": "Önizleme", - "test": "Test Et", - "hint": "Geçerli yapılandırmanızla API yanıtını önizlemek için Test Et'e tıklayın.", - "rawResponse": "Ham JSON yanıtı" - }, - "notification": { - "created": "“{name}” widget'ı başarıyla oluşturuldu.", - "updated": "“{name}” widget'ı başarıyla güncellendi.", - "deleted": "“{name}” widget'ı silindi.", - "imported": "Widget başarıyla içe aktarıldı.", - "aiPromptCopied": "Yapay zekâ istemi panoya kopyalandı", - "aiPromptDescription": "Herhangi bir yapay zekâ sohbet botuna (ChatGPT, Claude, Gemini...) yapıştırmak üzere önceden hazırlanmış bir istemi kopyalayın. İstem, yapay zekânın içe aktarmaya hazır bir JSON yapılandırması oluşturabilmesi için widget şemasının tamamını ve API yanıtınızı içerir.", - "aiPromptCopy": "Panoya kopyala", - "aiPromptNoResponse": "İpucu: Daha iyi sonuçlar için önce bir test çalıştırarak API yanıtınızı isteme ekleyin.", - "aiPromptCopyError": "İstem panoya kopyalanamadı. Tarayıcınız bu özelliği desteklemiyor olabilir.", - "createError": "Widget oluşturulamadı. API uç noktanızın erişilebilir olduğunu kontrol edin.", - "updateError": "Widget güncellenemedi. Değişiklikleriniz kaydedilmedi.", - "importError": "Widget içe aktarılamadı. Dosyanın geçerli bir özel widget JSON dışa aktarımı olduğundan emin olun.", - "exportError": "Widget dışa aktarılamadı.", - "duplicated": "“{name}” widget'ı çoğaltıldı.", - "duplicateError": "Widget çoğaltılamadı.", - "toggleError": "Widget durumu değiştirilemedi.", - "deleteError": "Widget silinemedi.", - "previewError": "Önizleme alınamadı. URL'yi kontrol edip yeniden deneyin.", - "executed": "Eylem başarıyla yürütüldü.", - "executeError": "Eylem başarısız oldu: {error}" - }, - "table": { - "name": "Ad", - "url": "URL", - "display": "Görüntüleme" - }, - "widget": { - "disabled": "Bu widget devre dışı" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "Paperless-ngx verileri alınamadı" } }, - "patchmon": { - "name": "PatchMon", - "description": "PatchMon'daki ana makine yama durumunun genel görünümü", - "title": "PatchMon İstatistikleri", - "totalHosts": "Toplam Ana Makine", - "hostsNeedingUpdates": "Güncelleme Gerekiyor", - "securityUpdates": "Güvenlik Güncellemeleri", - "upToDateHosts": "Güncel Ana Makineler", - "hostsWithSecurityUpdates": "Güvenlik Güncellemesi Olan Ana Makineler", - "recentUpdates24h": "Güncellemeler (24 sa.)", - "totalOutdatedPackages": "Güncel Olmayan Paketler", - "totalRepos": "Depolar", - "osDistribution": "İşletim Sistemi Dağılımı", - "compliance": "Yama Uyumluluğu", - "complianceRatio": "{upToDate} / {total}", - "lastUpdated": "Güncellendi: {time}", - "option": { - "showTotalHosts": { - "label": "Toplam ana makine sayısını göster", - "description": "İzlenen toplam ana makine sayısını gösterir" - }, - "showHostsNeedingUpdates": { - "label": "Güncelleme gereken ana makineleri göster", - "description": "En az bir güncel olmayan paketi bulunan ana makineleri gösterir" - }, - "showSecurityUpdates": { - "label": "Güvenlik güncellemelerini göster", - "description": "Kullanılabilir toplam güvenlik güncellemesi sayısını gösterir" - }, - "showUpToDateHosts": { - "label": "Güncel ana makineleri göster", - "description": "Güncel olmayan paketi bulunmayan ana makineleri gösterir" - }, - "showHostsWithSecurityUpdates": { - "label": "Güvenlik güncellemesi olan ana makineleri göster", - "description": "Güvenlik yaması gereken ana makineleri gösterir" - }, - "showRecentUpdates24h": { - "label": "Son güncellemeleri göster (24 sa.)", - "description": "Son 24 saatte uygulanan güncelleme sayısını gösterir" - }, - "showTotalOutdatedPackages": { - "label": "Güncel olmayan paketleri göster", - "description": "Tüm ana makinelerdeki güncel olmayan paketlerin toplam sayısını gösterir" - }, - "showTotalRepos": { - "label": "Depoları göster", - "description": "İzlenen etkin depo sayısını gösterir" - }, - "enableThresholdColors": { - "label": "Eşik renklerini etkinleştir", - "description": "İstatistik değerlerini önem düzeyi ön ayarlarına göre yeşil, sarı veya kırmızı renklendirir" - }, - "useCustomThresholds": { - "label": "Gelişmiş eşikler", - "description": "Her istatistik için uyarı ve kritik eşikleri mutlak sayılarla veya toplam ana makine yüzdesiyle özelleştirin" - }, - "thresholdMode": { - "option": { - "absolute": "Mutlak sayı", - "percent": "Toplam ana makinelerin yüzdesi" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "Güncelleme gereksinimi eşik modu", - "description": "Güncelleme gerekenlerin sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "Güncelleme gereksinimi uyarı eşiği", - "description": "Değer bu eşiğe ulaştığında sarı renge geçer" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "Güncelleme gereksinimi kritik eşiği", - "description": "Değer bu eşiğe ulaştığında kırmızı renge geçer" - }, - "securityUpdatesThresholdMode": { - "label": "Güvenlik güncellemeleri eşik modu", - "description": "Güvenlik güncellemesi sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır" - }, - "securityUpdatesWarningAt": { - "label": "Güvenlik güncellemeleri uyarı eşiği", - "description": "Değer bu eşiğe ulaştığında sarı renge geçer" - }, - "securityUpdatesCriticalAt": { - "label": "Güvenlik güncellemeleri kritik eşiği", - "description": "Değer bu eşiğe ulaştığında kırmızı renge geçer" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "Güvenlik güncellemesi olan ana makineler için eşik modu", - "description": "Ana makine sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "Güvenlik güncellemesi olan ana makineler için uyarı eşiği", - "description": "Değer bu eşiğe ulaştığında sarı renge geçer" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "Güvenlik güncellemesi olan ana makineler için kritik eşik", - "description": "Değer bu eşiğe ulaştığında kırmızı renge geçer" - }, - "upToDateHostsThresholdMode": { - "label": "Güncel ana makineler için eşik modu", - "description": "Güncel ana makine sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır" - }, - "upToDateHostsWarningAt": { - "label": "Güncel ana makineler için uyarı eşiği", - "description": "Değer bu eşikte veya üzerinde, ancak tam kapsamanın altındaysa sarı renge geçer" - }, - "upToDateHostsCriticalAt": { - "label": "Güncel ana makineler için kritik eşik", - "description": "Değer bu eşiğin altına düştüğünde kırmızı renge geçer" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "Güncel olmayan paketler için eşik modu", - "description": "Güncel olmayan paketlerin sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır" - }, - "totalOutdatedPackagesWarningAt": { - "label": "Güncel olmayan paketler için uyarı eşiği", - "description": "Değer bu eşiğe ulaştığında sarı renge geçer" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "Güncel olmayan paketler için kritik eşik", - "description": "Değer bu eşiğe ulaştığında kırmızı renge geçer" - }, - "showOsDistribution": { - "label": "İşletim sistemi dağılımını göster", - "description": "İzlenen ana makinelerin işletim sistemine göre dağılımını gösterir" - }, - "osDistributionLimit": { - "label": "İşletim sistemi dağılımı sınırı", - "description": "Gösterilecek en fazla işletim sistemi sayısı", - "option": { - "3": "İlk 3", - "5": "İlk 5", - "10": "İlk 10", - "all": "Tümü" - } - }, - "showOsVersion": { - "label": "İşletim sistemi sürümünü göster", - "description": "Mevcut olduğunda işletim sistemi sürümünü her dağılım etiketine ekler" - }, - "showComplianceHero": { - "label": "Uyumluluk özetini göster", - "description": "Güncel ana makinelerin yüzdesini gösteren bir uyumluluk halkası görüntüler" - }, - "osDisplayMode": { - "label": "İşletim sistemi görüntüleme modu", - "description": "İşletim sistemi dağılımının nasıl gösterileceğini seçin", - "option": { - "bars": "Yatay çubuklar", - "donut": "Halka grafik" - } - } - }, - "error": { - "internalServerError": "PatchMon verileri alınamadı" - } - }, - "bazarr": { - "name": "Bazarr", - "description": "Bazarr örneğinizdeki eksik altyazıların ve sağlık durumunun genel görünümü", - "episodes": "Eksik Bölümler", - "movies": "Eksik Filmler", - "providers": "Sağlayıcı Sorunları", - "status": "Sağlık Sorunları", - "option": { - "showMissingEpisodes": { - "label": "Eksik bölümleri göster", - "description": "Altyazısı eksik bölüm sayısını gösterir" - }, - "showMissingMovies": { - "label": "Eksik filmleri göster", - "description": "Altyazısı eksik film sayısını gösterir" - }, - "showProviderIssues": { - "label": "Sağlayıcı sorunlarını göster", - "description": "Sorun yaşayan altyazı sağlayıcılarının sayısını gösterir" - }, - "showHealthIssues": { - "label": "Sağlık sorunlarını göster", - "description": "Bazarr sağlık sorunlarının sayısını gösterir" - } - }, - "error": { - "internalServerError": "Bazarr verileri alınamadı" - } - }, "immich-serverStats": { "name": "Immich Sunucu İstatistikleri", "description": "Immich örneğiniz hakkında bilgiler", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "Eksik ve Kuyruktaki Medya", - "description": "Radarr ve Sonarr'daki eksik ve kuyruğa alınmış film ve bölümleri gösterir", - "option": { - "showMissing": { - "label": "Eksik öğeleri göster" - }, - "showQueued": { - "label": "Kuyruktaki öğeleri göster" - }, - "pageSize": { - "label": "Sayfa başına öğe" - } - }, - "tab": { - "missing": "Eksik", - "queued": "Kuyrukta" - }, - "type": { - "movie": "Film", - "episode": "Bölüm" - }, - "empty": { - "missing": "Eksik öğe yok", - "queued": "Kuyrukta öğe yok", - "noTabsEnabled": "Widget ayarlarında en az bir sekmeyi etkinleştirin" - }, - "timeLeft": "Kalan süre" - }, "rssFeed": { "name": "RSS Beslemeleri", "description": "Bir veya daha fazla RSS, ATOM veya JSON beslemesini takip edin ve görüntüleyin", @@ -3744,40 +3323,6 @@ "internalServerError": "Çalışma süresi verileri alınamadı" } }, - "traefik": { - "name": "Traefik", - "description": "Traefik yönlendiricilerinin, hizmetlerinin, ara yazılımlarının ve giriş noktalarının genel görünümü", - "option": { - "showTcp": { - "label": "TCP'yi göster" - }, - "showUdp": { - "label": "UDP'yi göster" - }, - "showEntryPoints": { - "label": "Giriş noktalarını göster" - } - }, - "instances": "Traefik örnekleri", - "versionUnknown": "Sürüm bilinmiyor", - "summary": { - "routers": "Yönlendiriciler", - "entryPoints": "Giriş noktaları" - }, - "resource": { - "routers": "Yönlendiriciler", - "services": "Hizmetler", - "middlewares": "Ara Yazılımlar" - }, - "status": { - "healthy": "Sağlıklı", - "errors": "{count} hata", - "warnings": "{count} uyarı" - }, - "error": { - "internalServerError": "Traefik verileri alınamadı" - } - }, "audioStats": { "name": "Ses İstatistikleri", "description": "Navidrome veya Audiobookshelf'ten kütüphane ve oynatma istatistikleri", @@ -3901,26 +3446,6 @@ "unhealthy": "Sağlıksız" } }, - "customApi": { - "name": "Özel API", - "description": "Özel yapılandırmayla herhangi bir harici API'den veri gösterir.", - "option": { - "definitionId": { - "label": "Tanım Kimliği" - }, - "refreshInterval": { - "label": "Yenileme aralığı", - "description": "Verilerin API'den hangi sıklıkta yeniden alınacağı (saniye)" - } - }, - "noDefinition": "Tanım seçilmedi", - "definitionNotFound": "Widget tanımı bulunamadı. Silinmiş olabilir.", - "noDisplayOutput": "Görüntülenecek çıktı yok", - "executeConfirm": "Bu eylemi yürütmek istediğinizden emin misiniz?", - "executing": "Yürütülüyor...", - "executeSuccess": "Eylem başarıyla yürütüldü", - "executeFailed": "Eylem başarısız oldu. Widget yapılandırmasını kontrol edin." - }, "beszelSystemTable": { "name": "Beszel Sistemleri (Tablo)", "description": "Sıralanabilir sütunlar ve durum göstergeleri ile tüm Beszel tarafından izlenen sistemlerin tablo görünümü", @@ -4171,6 +3696,256 @@ "subtitle": "Docker konteynerlerinin ağ trafiği" } } + }, + "patchmon": { + "name": "PatchMon", + "description": "PatchMon'daki ana makine yama durumunun genel görünümü", + "title": "PatchMon İstatistikleri", + "totalHosts": "Toplam Ana Makine", + "hostsNeedingUpdates": "Güncelleme Gerekiyor", + "securityUpdates": "Güvenlik Güncellemeleri", + "upToDateHosts": "Güncel Ana Makineler", + "hostsWithSecurityUpdates": "Güvenlik Güncellemesi Olan Ana Makineler", + "recentUpdates24h": "Güncellemeler (24 sa.)", + "totalOutdatedPackages": "Güncel Olmayan Paketler", + "totalRepos": "Depolar", + "osDistribution": "İşletim Sistemi Dağılımı", + "compliance": "Yama Uyumluluğu", + "complianceRatio": "{upToDate} / {total}", + "lastUpdated": "Güncellendi: {time}", + "option": { + "showTotalHosts": { + "label": "Toplam ana makine sayısını göster", + "description": "İzlenen toplam ana makine sayısını gösterir" + }, + "showHostsNeedingUpdates": { + "label": "Güncelleme gereken ana makineleri göster", + "description": "En az bir güncel olmayan paketi bulunan ana makineleri gösterir" + }, + "showSecurityUpdates": { + "label": "Güvenlik güncellemelerini göster", + "description": "Kullanılabilir toplam güvenlik güncellemesi sayısını gösterir" + }, + "showUpToDateHosts": { + "label": "Güncel ana makineleri göster", + "description": "Güncel olmayan paketi bulunmayan ana makineleri gösterir" + }, + "showHostsWithSecurityUpdates": { + "label": "Güvenlik güncellemesi olan ana makineleri göster", + "description": "Güvenlik yaması gereken ana makineleri gösterir" + }, + "showRecentUpdates24h": { + "label": "Son güncellemeleri göster (24 sa.)", + "description": "Son 24 saatte uygulanan güncelleme sayısını gösterir" + }, + "showTotalOutdatedPackages": { + "label": "Güncel olmayan paketleri göster", + "description": "Tüm ana makinelerdeki güncel olmayan paketlerin toplam sayısını gösterir" + }, + "showTotalRepos": { + "label": "Depoları göster", + "description": "İzlenen etkin depo sayısını gösterir" + }, + "enableThresholdColors": { + "label": "Eşik renklerini etkinleştir", + "description": "İstatistik değerlerini önem düzeyi ön ayarlarına göre yeşil, sarı veya kırmızı renklendirir" + }, + "useCustomThresholds": { + "label": "Gelişmiş eşikler", + "description": "Her istatistik için uyarı ve kritik eşikleri mutlak sayılarla veya toplam ana makine yüzdesiyle özelleştirin" + }, + "thresholdMode": { + "option": { + "absolute": "Mutlak sayı", + "percent": "Toplam ana makinelerin yüzdesi" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "Güncelleme gereksinimi eşik modu", + "description": "Güncelleme gerekenlerin sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "Güncelleme gereksinimi uyarı eşiği", + "description": "Değer bu eşiğe ulaştığında sarı renge geçer" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "Güncelleme gereksinimi kritik eşiği", + "description": "Değer bu eşiğe ulaştığında kırmızı renge geçer" + }, + "securityUpdatesThresholdMode": { + "label": "Güvenlik güncellemeleri eşik modu", + "description": "Güvenlik güncellemesi sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır" + }, + "securityUpdatesWarningAt": { + "label": "Güvenlik güncellemeleri uyarı eşiği", + "description": "Değer bu eşiğe ulaştığında sarı renge geçer" + }, + "securityUpdatesCriticalAt": { + "label": "Güvenlik güncellemeleri kritik eşiği", + "description": "Değer bu eşiğe ulaştığında kırmızı renge geçer" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "Güvenlik güncellemesi olan ana makineler için eşik modu", + "description": "Ana makine sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "Güvenlik güncellemesi olan ana makineler için uyarı eşiği", + "description": "Değer bu eşiğe ulaştığında sarı renge geçer" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "Güvenlik güncellemesi olan ana makineler için kritik eşik", + "description": "Değer bu eşiğe ulaştığında kırmızı renge geçer" + }, + "upToDateHostsThresholdMode": { + "label": "Güncel ana makineler için eşik modu", + "description": "Güncel ana makine sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır" + }, + "upToDateHostsWarningAt": { + "label": "Güncel ana makineler için uyarı eşiği", + "description": "Değer bu eşikte veya üzerinde, ancak tam kapsamanın altındaysa sarı renge geçer" + }, + "upToDateHostsCriticalAt": { + "label": "Güncel ana makineler için kritik eşik", + "description": "Değer bu eşiğin altına düştüğünde kırmızı renge geçer" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "Güncel olmayan paketler için eşik modu", + "description": "Güncel olmayan paketlerin sayısını mutlak değer veya toplam ana makinelerin yüzdesi olarak karşılaştırır" + }, + "totalOutdatedPackagesWarningAt": { + "label": "Güncel olmayan paketler için uyarı eşiği", + "description": "Değer bu eşiğe ulaştığında sarı renge geçer" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "Güncel olmayan paketler için kritik eşik", + "description": "Değer bu eşiğe ulaştığında kırmızı renge geçer" + }, + "showOsDistribution": { + "label": "İşletim sistemi dağılımını göster", + "description": "İzlenen ana makinelerin işletim sistemine göre dağılımını gösterir" + }, + "osDistributionLimit": { + "label": "İşletim sistemi dağılımı sınırı", + "description": "Gösterilecek en fazla işletim sistemi sayısı", + "option": { + "3": "İlk 3", + "5": "İlk 5", + "10": "İlk 10", + "all": "Tümü" + } + }, + "showOsVersion": { + "label": "İşletim sistemi sürümünü göster", + "description": "Mevcut olduğunda işletim sistemi sürümünü her dağılım etiketine ekler" + }, + "showComplianceHero": { + "label": "Uyumluluk özetini göster", + "description": "Güncel ana makinelerin yüzdesini gösteren bir uyumluluk halkası görüntüler" + }, + "osDisplayMode": { + "label": "İşletim sistemi görüntüleme modu", + "description": "İşletim sistemi dağılımının nasıl gösterileceğini seçin", + "option": { + "bars": "Yatay çubuklar", + "donut": "Halka grafik" + } + } + }, + "error": { + "internalServerError": "PatchMon verileri alınamadı" + } + }, + "bazarr": { + "name": "Bazarr", + "description": "Bazarr örneğinizdeki eksik altyazıların ve sağlık durumunun genel görünümü", + "episodes": "Eksik Bölümler", + "movies": "Eksik Filmler", + "providers": "Sağlayıcı Sorunları", + "status": "Sağlık Sorunları", + "option": { + "showMissingEpisodes": { + "label": "Eksik bölümleri göster", + "description": "Altyazısı eksik bölüm sayısını gösterir" + }, + "showMissingMovies": { + "label": "Eksik filmleri göster", + "description": "Altyazısı eksik film sayısını gösterir" + }, + "showProviderIssues": { + "label": "Sağlayıcı sorunlarını göster", + "description": "Sorun yaşayan altyazı sağlayıcılarının sayısını gösterir" + }, + "showHealthIssues": { + "label": "Sağlık sorunlarını göster", + "description": "Bazarr sağlık sorunlarının sayısını gösterir" + } + }, + "error": { + "internalServerError": "Bazarr verileri alınamadı" + } + }, + "mediaMissing": { + "name": "Eksik ve Kuyruktaki Medya", + "description": "Radarr ve Sonarr'daki eksik ve kuyruğa alınmış film ve bölümleri gösterir", + "option": { + "showMissing": { + "label": "Eksik öğeleri göster" + }, + "showQueued": { + "label": "Kuyruktaki öğeleri göster" + }, + "pageSize": { + "label": "Sayfa başına öğe" + } + }, + "tab": { + "missing": "Eksik", + "queued": "Kuyrukta" + }, + "type": { + "movie": "Film", + "episode": "Bölüm" + }, + "empty": { + "missing": "Eksik öğe yok", + "queued": "Kuyrukta öğe yok", + "noTabsEnabled": "Widget ayarlarında en az bir sekmeyi etkinleştirin" + }, + "timeLeft": "Kalan süre" + }, + "traefik": { + "name": "Traefik", + "description": "Traefik yönlendiricilerinin, hizmetlerinin, ara yazılımlarının ve giriş noktalarının genel görünümü", + "option": { + "showTcp": { + "label": "TCP'yi göster" + }, + "showUdp": { + "label": "UDP'yi göster" + }, + "showEntryPoints": { + "label": "Giriş noktalarını göster" + } + }, + "instances": "Traefik örnekleri", + "versionUnknown": "Sürüm bilinmiyor", + "summary": { + "routers": "Yönlendiriciler", + "entryPoints": "Giriş noktaları" + }, + "resource": { + "routers": "Yönlendiriciler", + "services": "Hizmetler", + "middlewares": "Ara Yazılımlar" + }, + "status": { + "healthy": "Sağlıklı", + "errors": "{count} hata", + "warnings": "{count} uyarı" + }, + "error": { + "internalServerError": "Traefik verileri alınamadı" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Ana Sayfa", "boards": "Paneller", "apps": "Uygulamalar", "integrations": "Entegrasyonlar", - "customWidgets": "Özel Widget'lar", "searchEngies": "Arama Motorları", "medias": "Medyalar", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Yönet", "boards": { "label": "Paneller" @@ -5728,18 +5506,6 @@ "label": "Düzenle" } }, - "custom-widgets": { - "label": "Özel widget'lar", - "new": { - "label": "Yeni" - }, - "edit": { - "label": "Düzenle", - "flow": { - "label": "Akış" - } - } - }, "users": { "label": "Kullanıcılar", "create": { diff --git a/packages/translation/src/lang/uk.json b/packages/translation/src/lang/uk.json index fd87688e4..bfda23c7b 100644 --- a/packages/translation/src/lang/uk.json +++ b/packages/translation/src/lang/uk.json @@ -691,206 +691,11 @@ "customWidget": { "page": { "list": { - "title": "Власні віджети", - "noResults": "Поки що немає власних віджетів. Створіть свій перший!", - "loading": "Завантаження..." - }, - "create": { - "title": "Створити власний віджет", - "subtitle": "Визначте URL-адресу API, автентифікацію та спосіб показу даних відповіді." - }, - "edit": { - "title": "Редагувати власний віджет" + "title": "Власні віджети" } }, - "action": { - "create": "Створити", - "import": "Імпорт", - "save": "Зберегти", - "delete": "Видалити власний віджет", - "deleteConfirm": "Ви впевнені, що хочете видалити \"{name}\"? Цю дію неможливо скасувати.", - "export": "Експорт", - "addMapping": "Додати зіставлення", - "addColumn": "Додати стовпець", - "edit": "Редагувати", - "removeMapping": "Видалити зіставлення", - "removeColumn": "Видалити стовпець", - "addItem": "Додати елемент", - "removeItem": "Видалити елемент", - "addBar": "Додати бар", - "duplicate": "Дублікат", - "copyAiPrompt": "Копіювати запит AI", - "enable": "Увімкнути", - "disable": "Вимкнути", - "menu": "Дії" - }, - "field": { - "name": "Назва", - "description": "Опис", - "iconUrl": "URL іконки", - "url": "URL-адреса", - "authType": "Тип авторизації", - "headerName": "Назва параметра заголовок/запиту", - "method": "Метод", - "requestBody": "Текст запиту", - "displayType": "Тип для показу", - "jsonPath": "Шлях до JSON", - "jsonPathHint": "Використовуйте синтаксис JSONPath для вилучення значень, наприклад, $.data.temperature або $.items[0].name", - "label": "Мітка", - "unit": "Одиниця", - "mappings": "Зіставлення", - "tablePath": "Шлях масиву JSON", - "tablePathHint": "Шлях до масиву у відповідь, наприклад, $.data.items", - "columns": "Стовпці", - "header": "Заголовок", - "items": "Елементи", - "gridColumns": "Стовпці сітки", - "cardStyle": "Стиль картки", - "bars": "Бари", - "valuePath": "Значення JSON шлях", - "maxPath": "Макс. значення JSON шляху", - "showPercentage": "Показувати відсоток", - "barSize": "Розмір панелі", - "goodValues": "Хороші значення (розділені комами)", - "dotSize": "Розмір точки", - "valueSize": "Розмір значення", - "labelPosition": "Позиція мітки", - "kvLayout": "Макет", - "striped": "Смугасті рядки", - "compact": "Компактний режим", - "maxHeight": "Макс висота (пікс.)", - "color": "Колір", - "buttonLabel": "Підпис кнопки", - "buttonColor": "Колір кнопки", - "confirmText": "Текст підтвердження", - "confirmTextHint": "Якщо встановлено, перед виконанням запиту з’явиться діалогове вікно підтвердження", - "successMessage": "Повідомлення про успіх", - "successMessageHint": "Повідомлення яке відображається після успішного виконання", - "enabled": "Увімкнено", - "template": { - "label": "Шаблон JSX", - "description": "Шаблон Mantine JSX. Доступ до полів відповіді API через прив'язки даних (наприклад, data.name). Використовуйте лише компоненти з білого списку. Заборонено: constructor, __proto__, eval, Function, window, document." - } - }, - "placeholder": { - "exampleLabel": "Температура ЦП", - "exampleLabelShort": "Темп процесора", - "exampleHeader": "Назва", - "exampleUnit": "°C", - "iconUrl": "https://...", - "url": "https://api.example.com/api/v1/status", - "headerName": "X-API-Key", - "jsonPath": "$.data.value", - "tablePath": "$.data.items", - "columnJsonPath": "$.name", - "valuePath": "$.data.used", - "maxPath": "$.data.total", - "goodValues": "онлайн, правда, вгору", - "color": "синій" - }, - "cardStyleOption": { - "filled": "Заповнений", - "outline": "Контур", - "subtle": "Тонкий" - }, - "layoutOption": { - "list": "Список", - "grid": "Сітка" - }, - "sizeOption": { - "sm": "Малий", - "md": "Середній", - "lg": "Великий", - "xl": "Дуже великий" - }, - "labelPositionOption": { - "above": "Вище", - "below": "Нижче" - }, - "fieldset": { - "general": "Загальне", - "connection": "API підключення", - "display": "Конфігурації дисплея" - }, - "displayTypeDescription": { - "singleValue": "Показати одне витягнуте значення з міткою та одиницею вимірювання", - "keyValue": "Показати кілька позначених значень поруч", - "table": "Показати рядки даних у форматі таблиці", - "statGrid": "Кольорові картки статистики в сітці — як-от віджети Pi-Hole або Speedtest", - "progressBars": "Індикатори виконання, що показують використання або завершення — для диска, пам'яті, квот", - "statusIndicator": "Кольорові крапки стану показують онлайн/оффлайн або охорони здоров'я", - "countGrid": "Компактне число + лічильники міток у вигляді сітки", - "raw": "Гарно надрукований JSON-вивід для налагодження", - "actionButton": "Кнопка яка виконує запит при натисканні", - "customJsx": "Користувацький макет JSX з пов'язування повним API даних з білого списку" - }, - "method": { - "GET": "ОТРИМАТИ", - "POST": "СТВОРИТИ", - "PUT": "Розміщення", - "DELETE": "ВИДАЛИТИ", - "PATCH": "ПАТЧ" - }, - "authType": { - "none": "Немає", - "bearer": "Пред'явити токен", - "basic": "Базова авторизація", - "apiKeyHeader": "Ключ API (Заголовок)", - "apiKeyQuery": "Ключ API (запит)" - }, - "displayType": { - "singleValue": "Одиночні Значення", - "keyValue": "Значення ключа", - "table": "Таблиця", - "statGrid": "Статистична сітка", - "progressBars": "Індикатори прогресу", - "statusIndicator": "Індикатор стану", - "countGrid": "Кількість сіток", - "raw": "Необроблений JSON", - "actionButton": "Кнопка дії", - "customJsx": "Користувацький JSX" - }, - "secret": { - "apiKey": "Ключ API / Токен", - "username": "Ім'я користувача", - "password": "Пароль", - "savedPlaceholder": "• • • • • • (збережено, залиште порожнім, щоб зберегти)" - }, - "preview": { - "title": "Попередній перегляд", - "test": "Перевірка", - "hint": "Натисніть Тест, щоб переглянути відповідь API з поточною конфігурацією.", - "rawResponse": "Необроблена відповідь JSON" - }, "notification": { - "created": "Віджет \"{name}\" успішно створено.", - "updated": "Віджет \"{name}\" успішно оновлено.", - "deleted": "Віджет \"{name}\" видалено.", - "imported": "Віджет успішно імпортовано.", - "aiPromptCopied": "Запит ШІ скопійовано до буферу обміну", - "aiPromptDescription": "Скопіюйте запит на вставку в будь-який AI чатбот (ChatGPT, Claude, Gemini ...). Вона включає в себе повну схему віджетів і вашу API відповідь, щоб ШІ могла генерувати конфігурацію AI для вашого коректного імпортування.", - "aiPromptCopy": "Скопіювати в буфер обміну", - "aiPromptNoResponse": "Порада: Спочатку запустіть тест, щоб включити відповідь API в командний рядок для отримання кращих результатів.", - "aiPromptCopyError": "Не вдалося скопіювати запит до буфера обміну. Можливо, ваш браузер не підтримує цю функцію.", - "createError": "Не вдалося створити віджет. Перевірте кінцеву точку API.", - "updateError": "Неможливо оновити віджет. Зміни не збережено.", - "importError": "Неможливо імпортувати віджет. Переконайтеся, що файл є допустимим експортом користувацьких віджетів JSON.", - "exportError": "Не вдалося експортувати віджет.", - "duplicated": "Віджет \"{name}\" продубльовано.", - "duplicateError": "Не вдалося продублювати віджет.", - "toggleError": "Не вдалося змінити стан віджету.", - "deleteError": "Не вдалося видалити віджет.", - "previewError": "Не вдалося отримати попередній перегляд. Перевірте URL-адресу та повторіть спробу.", - "executed": "Дію успішно виконано.", - "executeError": "Дію не виконано: {error}" - }, - "table": { - "name": "Назва", - "url": "URL", - "display": "Показати" - }, - "widget": { - "disabled": "Цей віджет вимкнено" + "toggleError": "Не вдалося змінити стан віджету." } }, "integration": { @@ -2828,193 +2633,6 @@ "internalServerError": "Не вдалося отримати дані Paperless-ngx" } }, - "patchmon": { - "name": "ПатчМон", - "description": "Огляд стану патчів хоста від PatchMon", - "title": "Статистика PatchMon", - "totalHosts": "Всього хостів", - "hostsNeedingUpdates": "Потребує оновлення", - "securityUpdates": "Оновлення безпеки", - "upToDateHosts": "Оновлені хости", - "hostsWithSecurityUpdates": "Хости з оновленнями безпеки", - "recentUpdates24h": "Оновлення (24г)", - "totalOutdatedPackages": "Застарілі пакети", - "totalRepos": "Репозитарії", - "osDistribution": "Розподіл ОС", - "compliance": "Відповідність патчам", - "complianceRatio": "{upToDate} / {total}", - "lastUpdated": "Оновлено {time}", - "option": { - "showTotalHosts": { - "label": "Показати хости загалом", - "description": "Відображати загальну кількість контрольованих хостів" - }, - "showHostsNeedingUpdates": { - "label": "Показувати потрібні оновлення хостів", - "description": "Відображати хости з принаймні одним застарілим пакетом" - }, - "showSecurityUpdates": { - "label": "Показати оновлення безпеки", - "description": "Відображати загальну кількість доступних оновлень безпеки" - }, - "showUpToDateHosts": { - "label": "Показувати актуальні хости", - "description": "Відображати хостингові системи без застарілих пакетів" - }, - "showHostsWithSecurityUpdates": { - "label": "Показувати хости з оновленнями безпеки", - "description": "Показувати хости, які потребують патчів безпеки" - }, - "showRecentUpdates24h": { - "label": "Показати останні оновлення (24h)", - "description": "Відображати кількість оновлень, застосованих за останні 24 години" - }, - "showTotalOutdatedPackages": { - "label": "Показати застарілі пакети", - "description": "Відображати загальну кількість застарілих пакетів у всіх хостах" - }, - "showTotalRepos": { - "label": "Показати репозиторії", - "description": "Відображати кількість активних репозиторіїв, що відслідковуються" - }, - "enableThresholdColors": { - "label": "Увімкнути кольори порогових значень", - "description": "Значення колірних характеристик: зелений, жовтий або червоний, залежно від пресетів серйозності" - }, - "useCustomThresholds": { - "label": "Розширені пороги", - "description": "Налаштуйте пороги попереджень та критичних значень для кожної статистики, використовуючи абсолютні показники або відсотки від загальної кількості хостів" - }, - "thresholdMode": { - "option": { - "absolute": "Абсолютна кількість", - "percent": "Відсоток від загальної кількості хостів" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "Потрібен поріг оновлення", - "description": "Порівняйте оновлення як абсолютне значення або відсоток від загальної кількості хостів" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "Поріг попередження про нові оновлення", - "description": "Вмикається жовтий колір, коли значення досягає цього порогового значення" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "Потребує оновлення критичного порогу", - "description": "Вмикається червоний коли значення досягає цього порогу" - }, - "securityUpdatesThresholdMode": { - "label": "Режим оновлення системи безпеки", - "description": "Порівняйте оновлення безпеки як абсолютне значення або відсоток від загальної кількості хостів" - }, - "securityUpdatesWarningAt": { - "label": "Поріг попередження про оновлення безпеки", - "description": "Вмикається жовтий колір, коли значення досягає цього порогового значення" - }, - "securityUpdatesCriticalAt": { - "label": "Критичний поріг оновлення системи безпеки", - "description": "Вмикається червоний коли значення досягає цього порогу" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "Хости з режимом порогу оновлень безпеки", - "description": "Порівняйте кількість хостів як абсолютне значення або відсоток від загальної кількості хостів" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "Хости з попередженням про оновлення безпеки", - "description": "Вмикається жовтий колір коли значення досягає цього порогу" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "Хости з критичним порогом оновлення безпеки", - "description": "Вмикається червоний коли значення досягає цього порогу" - }, - "upToDateHostsThresholdMode": { - "label": "Оновлений режим порогового хостів", - "description": "Порівняйте актуальний хост як абсолютне значення або відсоток від загальної кількості хостів" - }, - "upToDateHostsWarningAt": { - "label": "Поріг попередження для актуальних хостів", - "description": "Вмикається жовтий колір, коли значення дорівнює або перевищує цей поріг, але нижче повного покриття." - }, - "upToDateHostsCriticalAt": { - "label": "Критичний поріг для оновлених хостів", - "description": "Вмикається червоний, коли значення падає нижче цього порогу" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "Режим порогу застарілих пакетів", - "description": "Порівняйте застарілі пакети як абсолютне значення або відсоток від загальної кількості хостів" - }, - "totalOutdatedPackagesWarningAt": { - "label": "Поріг попередження про застарілі пакети", - "description": "Вмикається жовтий, коли значення досягає цього порогу" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "Критичний поріг застарілих пакетів", - "description": "Вмикається червоний коли значення досягає цього порогу" - }, - "showOsDistribution": { - "label": "Показати розподіл ОС", - "description": "Показати розподіл контрольованих хостів операційною системою" - }, - "osDistributionLimit": { - "label": "Обмеження розподілу ОС", - "description": "Максимальна кількість операційних систем для відображення", - "option": { - "3": "Топ 3", - "5": "Тор 5", - "10": "Топ 10", - "all": "Усі" - } - }, - "showOsVersion": { - "label": "Показати версію ОС", - "description": "Додавати версію ОС до кожної мітки дистрибуції, коли вона стане доступною" - }, - "showComplianceHero": { - "label": "Показати героя відповідності", - "description": "Відображати кільце відповідності, яке показує відсоток оновлених хостів" - }, - "osDisplayMode": { - "label": "Режим відображення ОС", - "description": "Виберіть спосіб відображення дистрибутива операційної системи", - "option": { - "bars": "Горизонтальні смуги", - "donut": "Кільцева діаграма" - } - } - }, - "error": { - "internalServerError": "Не вдалося отримати дані PatchMon" - } - }, - "bazarr": { - "name": "Bazarr", - "description": "Огляд відсутніх субтитрів та стану справності вашого екземпляра Bazarr", - "episodes": "Відсутні епізоди", - "movies": "Відсутні фільми", - "providers": "Проблеми p постачальником", - "status": "Проблеми зі здоров'ям", - "option": { - "showMissingEpisodes": { - "label": "Показати відсутні епізоди", - "description": "Відображати кількість епізодів без субтититрів" - }, - "showMissingMovies": { - "label": "Показати відсутні фільми", - "description": "Відобразити кількість фільмів без субтитрів" - }, - "showProviderIssues": { - "label": "Показати проблеми постачальника", - "description": "Відображати кількість постачальника субтитрів з проблемами" - }, - "showHealthIssues": { - "label": "Показувати проблеми зі здоров’ям", - "description": "Відображати кількість проблем зі здоров’ям Bazarr" - } - }, - "error": { - "internalServerError": "Не вдалося отримати дані Bazarr" - } - }, "immich-serverStats": { "name": "Статистика Immich на сервері", "description": "Інформація про Ваш екземпляр Immich", @@ -3387,35 +3005,6 @@ } } }, - "mediaMissing": { - "name": "Відсутня медіа в черзі", - "description": "Показує відсутні і в черзі фільми і епізоди з Radarr і Sonarr", - "option": { - "showMissing": { - "label": "Показати відсутні елементи" - }, - "showQueued": { - "label": "Показати елементи в черзі" - }, - "pageSize": { - "label": "Елементів на сторінці" - } - }, - "tab": { - "missing": "Відсутні", - "queued": "У черзі" - }, - "type": { - "movie": "Фільм", - "episode": "Епізод" - }, - "empty": { - "missing": "Немає відсутніх елементів", - "queued": "Немає елементів у черзі", - "noTabsEnabled": "Увімкнути принаймні одну вкладку в налаштуваннях віджету" - }, - "timeLeft": "Залишилося часу" - }, "rssFeed": { "name": "RSS-канали", "description": "Моніторинг та відображення однієї або кількох загальних RSS-, ATOM- або JSON-стрічок", @@ -3744,40 +3333,6 @@ "internalServerError": "Не вдалося отримати дані про час роботи" } }, - "traefik": { - "name": "Трафік", - "description": "Огляд маршрутизаторів, сервісів, проміжного програмного забезпечення та точок входу Traefik", - "option": { - "showTcp": { - "label": "Показати TCP" - }, - "showUdp": { - "label": "Show UDP" - }, - "showEntryPoints": { - "label": "Показувати точки входу" - } - }, - "instances": "Traefik екземпляри", - "versionUnknown": "Версія невідома", - "summary": { - "routers": "Маршрутизатори", - "entryPoints": "Точки входу" - }, - "resource": { - "routers": "Маршрутизатори", - "services": "Служби", - "middlewares": "Проміжне програмне забезпечення" - }, - "status": { - "healthy": "Здоровий", - "errors": "{count} помилок", - "warnings": "{count} застережень" - }, - "error": { - "internalServerError": "Неможливо отримати дані Traefik" - } - }, "audioStats": { "name": "Статистика аудіо", "description": "Бібліотека і відтворення статистики з Navidrome або Audiobookf", @@ -3901,26 +3456,6 @@ "unhealthy": "Нездоровий" } }, - "customApi": { - "name": "Користувацький API", - "description": "Відображення даних з будь-якої зовнішньої API з користувальницької конфігурації.", - "option": { - "definitionId": { - "label": "Ідентифікатор визначення" - }, - "refreshInterval": { - "label": "Інтервал оновлення", - "description": "Як часто слід оновлювати дані з API (в секундах)" - } - }, - "noDefinition": "Не обрано визначення", - "definitionNotFound": "Визначення віджета не знайдено. Можливо, його видалено.", - "noDisplayOutput": "Без виводу на екран", - "executeConfirm": "Ви впевнені, що хочете виконати цю дію?", - "executing": "Виконання...", - "executeSuccess": "Дія успішно виконана", - "executeFailed": "Не вдалося виконати дію. Перевірте налаштування віджету." - }, "beszelSystemTable": { "name": "Beszel системи (Таблиця)", "description": "Вид таблиць всіх систем, що контролюються в Beszel, з сортованими стовпцями і індикатори стану", @@ -4171,6 +3706,256 @@ "subtitle": "Мережевий трафік Docker контейнерів" } } + }, + "patchmon": { + "name": "ПатчМон", + "description": "Огляд стану патчів хоста від PatchMon", + "title": "Статистика PatchMon", + "totalHosts": "Всього хостів", + "hostsNeedingUpdates": "Потребує оновлення", + "securityUpdates": "Оновлення безпеки", + "upToDateHosts": "Оновлені хости", + "hostsWithSecurityUpdates": "Хости з оновленнями безпеки", + "recentUpdates24h": "Оновлення (24г)", + "totalOutdatedPackages": "Застарілі пакети", + "totalRepos": "Репозитарії", + "osDistribution": "Розподіл ОС", + "compliance": "Відповідність патчам", + "complianceRatio": "{upToDate} / {total}", + "lastUpdated": "Оновлено {time}", + "option": { + "showTotalHosts": { + "label": "Показати хости загалом", + "description": "Відображати загальну кількість контрольованих хостів" + }, + "showHostsNeedingUpdates": { + "label": "Показувати потрібні оновлення хостів", + "description": "Відображати хости з принаймні одним застарілим пакетом" + }, + "showSecurityUpdates": { + "label": "Показати оновлення безпеки", + "description": "Відображати загальну кількість доступних оновлень безпеки" + }, + "showUpToDateHosts": { + "label": "Показувати актуальні хости", + "description": "Відображати хостингові системи без застарілих пакетів" + }, + "showHostsWithSecurityUpdates": { + "label": "Показувати хости з оновленнями безпеки", + "description": "Показувати хости, які потребують патчів безпеки" + }, + "showRecentUpdates24h": { + "label": "Показати останні оновлення (24h)", + "description": "Відображати кількість оновлень, застосованих за останні 24 години" + }, + "showTotalOutdatedPackages": { + "label": "Показати застарілі пакети", + "description": "Відображати загальну кількість застарілих пакетів у всіх хостах" + }, + "showTotalRepos": { + "label": "Показати репозиторії", + "description": "Відображати кількість активних репозиторіїв, що відслідковуються" + }, + "enableThresholdColors": { + "label": "Увімкнути кольори порогових значень", + "description": "Значення колірних характеристик: зелений, жовтий або червоний, залежно від пресетів серйозності" + }, + "useCustomThresholds": { + "label": "Розширені пороги", + "description": "Налаштуйте пороги попереджень та критичних значень для кожної статистики, використовуючи абсолютні показники або відсотки від загальної кількості хостів" + }, + "thresholdMode": { + "option": { + "absolute": "Абсолютна кількість", + "percent": "Відсоток від загальної кількості хостів" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "Потрібен поріг оновлення", + "description": "Порівняйте оновлення як абсолютне значення або відсоток від загальної кількості хостів" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "Поріг попередження про нові оновлення", + "description": "Вмикається жовтий колір, коли значення досягає цього порогового значення" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "Потребує оновлення критичного порогу", + "description": "Вмикається червоний коли значення досягає цього порогу" + }, + "securityUpdatesThresholdMode": { + "label": "Режим оновлення системи безпеки", + "description": "Порівняйте оновлення безпеки як абсолютне значення або відсоток від загальної кількості хостів" + }, + "securityUpdatesWarningAt": { + "label": "Поріг попередження про оновлення безпеки", + "description": "Вмикається жовтий колір, коли значення досягає цього порогового значення" + }, + "securityUpdatesCriticalAt": { + "label": "Критичний поріг оновлення системи безпеки", + "description": "Вмикається червоний коли значення досягає цього порогу" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "Хости з режимом порогу оновлень безпеки", + "description": "Порівняйте кількість хостів як абсолютне значення або відсоток від загальної кількості хостів" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "Хости з попередженням про оновлення безпеки", + "description": "Вмикається жовтий колір коли значення досягає цього порогу" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "Хости з критичним порогом оновлення безпеки", + "description": "Вмикається червоний коли значення досягає цього порогу" + }, + "upToDateHostsThresholdMode": { + "label": "Оновлений режим порогового хостів", + "description": "Порівняйте актуальний хост як абсолютне значення або відсоток від загальної кількості хостів" + }, + "upToDateHostsWarningAt": { + "label": "Поріг попередження для актуальних хостів", + "description": "Вмикається жовтий колір, коли значення дорівнює або перевищує цей поріг, але нижче повного покриття." + }, + "upToDateHostsCriticalAt": { + "label": "Критичний поріг для оновлених хостів", + "description": "Вмикається червоний, коли значення падає нижче цього порогу" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "Режим порогу застарілих пакетів", + "description": "Порівняйте застарілі пакети як абсолютне значення або відсоток від загальної кількості хостів" + }, + "totalOutdatedPackagesWarningAt": { + "label": "Поріг попередження про застарілі пакети", + "description": "Вмикається жовтий, коли значення досягає цього порогу" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "Критичний поріг застарілих пакетів", + "description": "Вмикається червоний коли значення досягає цього порогу" + }, + "showOsDistribution": { + "label": "Показати розподіл ОС", + "description": "Показати розподіл контрольованих хостів операційною системою" + }, + "osDistributionLimit": { + "label": "Обмеження розподілу ОС", + "description": "Максимальна кількість операційних систем для відображення", + "option": { + "3": "Топ 3", + "5": "Тор 5", + "10": "Топ 10", + "all": "Усі" + } + }, + "showOsVersion": { + "label": "Показати версію ОС", + "description": "Додавати версію ОС до кожної мітки дистрибуції, коли вона стане доступною" + }, + "showComplianceHero": { + "label": "Показати героя відповідності", + "description": "Відображати кільце відповідності, яке показує відсоток оновлених хостів" + }, + "osDisplayMode": { + "label": "Режим відображення ОС", + "description": "Виберіть спосіб відображення дистрибутива операційної системи", + "option": { + "bars": "Горизонтальні смуги", + "donut": "Кільцева діаграма" + } + } + }, + "error": { + "internalServerError": "Не вдалося отримати дані PatchMon" + } + }, + "bazarr": { + "name": "Bazarr", + "description": "Огляд відсутніх субтитрів та стану справності вашого екземпляра Bazarr", + "episodes": "Відсутні епізоди", + "movies": "Відсутні фільми", + "providers": "Проблеми p постачальником", + "status": "Проблеми зі здоров'ям", + "option": { + "showMissingEpisodes": { + "label": "Показати відсутні епізоди", + "description": "Відображати кількість епізодів без субтититрів" + }, + "showMissingMovies": { + "label": "Показати відсутні фільми", + "description": "Відобразити кількість фільмів без субтитрів" + }, + "showProviderIssues": { + "label": "Показати проблеми постачальника", + "description": "Відображати кількість постачальника субтитрів з проблемами" + }, + "showHealthIssues": { + "label": "Показувати проблеми зі здоров’ям", + "description": "Відображати кількість проблем зі здоров’ям Bazarr" + } + }, + "error": { + "internalServerError": "Не вдалося отримати дані Bazarr" + } + }, + "mediaMissing": { + "name": "Відсутня медіа в черзі", + "description": "Показує відсутні і в черзі фільми і епізоди з Radarr і Sonarr", + "option": { + "showMissing": { + "label": "Показати відсутні елементи" + }, + "showQueued": { + "label": "Показати елементи в черзі" + }, + "pageSize": { + "label": "Елементів на сторінці" + } + }, + "tab": { + "missing": "Відсутні", + "queued": "У черзі" + }, + "type": { + "movie": "Фільм", + "episode": "Епізод" + }, + "empty": { + "missing": "Немає відсутніх елементів", + "queued": "Немає елементів у черзі", + "noTabsEnabled": "Увімкнути принаймні одну вкладку в налаштуваннях віджету" + }, + "timeLeft": "Залишилося часу" + }, + "traefik": { + "name": "Трафік", + "description": "Огляд маршрутизаторів, сервісів, проміжного програмного забезпечення та точок входу Traefik", + "option": { + "showTcp": { + "label": "Показати TCP" + }, + "showUdp": { + "label": "Show UDP" + }, + "showEntryPoints": { + "label": "Показувати точки входу" + } + }, + "instances": "Traefik екземпляри", + "versionUnknown": "Версія невідома", + "summary": { + "routers": "Маршрутизатори", + "entryPoints": "Точки входу" + }, + "resource": { + "routers": "Маршрутизатори", + "services": "Служби", + "middlewares": "Проміжне програмне забезпечення" + }, + "status": { + "healthy": "Здоровий", + "errors": "{count} помилок", + "warnings": "{count} застережень" + }, + "error": { + "internalServerError": "Неможливо отримати дані Traefik" + } } }, "widgetPreview": { @@ -4551,11 +4336,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "Головна", "boards": "Дошки", "apps": "Додатки", "integrations": "Інтеграції", - "customWidgets": "Власні віджети", "searchEngies": "Пошукові системи", "medias": "Медіа", "users": { @@ -5694,6 +5479,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "Керувати", "boards": { "label": "Дошки" @@ -5728,18 +5516,6 @@ "label": "Редагувати" } }, - "custom-widgets": { - "label": "Користувальницькі віджети", - "new": { - "label": "Новий" - }, - "edit": { - "label": "Редагувати", - "flow": { - "label": "Потік" - } - } - }, "users": { "label": "Користувачі", "create": { diff --git a/packages/translation/src/lang/zh.json b/packages/translation/src/lang/zh.json index 58e679768..310cbf845 100644 --- a/packages/translation/src/lang/zh.json +++ b/packages/translation/src/lang/zh.json @@ -688,211 +688,6 @@ "add": "新增應用程式" } }, - "customWidget": { - "page": { - "list": { - "title": "自訂小工具", - "noResults": "尚無自訂小工具。建立您的第一個!", - "loading": "正在讀取……" - }, - "create": { - "title": "建立自訂小工具", - "subtitle": "定義 API URL、驗證方式以及如何顯示回應資料。" - }, - "edit": { - "title": "編輯自訂小工具" - } - }, - "action": { - "create": "建立", - "import": "匯入", - "save": "儲存", - "delete": "刪除自訂小工具", - "deleteConfirm": "確定要刪除 \"{name}\" 嗎?此動作無法復原。", - "export": "匯出", - "addMapping": "新增對應", - "addColumn": "新增欄", - "edit": "編輯", - "removeMapping": "移除對應", - "removeColumn": "移除欄", - "addItem": "新增項目", - "removeItem": "移除項目", - "addBar": "新增長條", - "duplicate": "複製", - "copyAiPrompt": "複製 AI 提示", - "enable": "啟用", - "disable": "停用", - "menu": "動作" - }, - "field": { - "name": "名稱", - "description": "描述", - "iconUrl": "圖示網址", - "url": "網址", - "authType": "驗證類型", - "headerName": "標頭/查詢參數名稱", - "method": "方法", - "requestBody": "請求主體", - "displayType": "顯示類型", - "jsonPath": "JSON 路徑", - "jsonPathHint": "使用 JSONPath 語法來擷取值,例如 $.data.temperature 或 $.items[0].name", - "label": "標籤", - "unit": "單位", - "mappings": "對應", - "tablePath": "陣列 JSON 路徑", - "tablePathHint": "回應中陣列的路徑,例如 $.data.items", - "columns": "欄", - "header": "標頭", - "items": "項目", - "gridColumns": "網格欄", - "cardStyle": "卡片樣式", - "bars": "長條", - "valuePath": "值 JSON 路徑", - "maxPath": "最大值 JSON 路徑", - "showPercentage": "顯示百分比", - "barSize": "長條大小", - "goodValues": "良好值 (逗號分隔)", - "dotSize": "點大小", - "valueSize": "值大小", - "labelPosition": "標籤位置", - "kvLayout": "佈局", - "striped": "條紋列", - "compact": "精簡模式", - "maxHeight": "最大高度 (像素)", - "color": "顏色", - "buttonLabel": "按鈕標籤", - "buttonColor": "按鈕顏色", - "confirmText": "確認文字", - "confirmTextHint": "若設定,執行請求前會顯示確認對話框", - "successMessage": "成功訊息", - "successMessageHint": "執行成功後顯示的訊息", - "enabled": "已啟用", - "template": { - "label": "JSX 樣板", - "description": "Mantine JSX 樣板。透過資料綁定存取 API 回應欄位 (例如 data.name)。僅使用白名單中的組件。禁止: constructor, __proto__, eval, Function, window, document。" - } - }, - "placeholder": { - "exampleLabel": "CPU 溫度", - "exampleLabelShort": "CPU 溫度", - "exampleHeader": "名稱", - "exampleUnit": "°C", - "iconUrl": "https://……", - "url": "https://api.example.com/api/v1/status", - "headerName": "X-API-Key", - "jsonPath": "$.data.value", - "tablePath": "$.data.items", - "columnJsonPath": "$.name", - "valuePath": "$.data.used", - "maxPath": "$.data.total", - "goodValues": "online, true, up", - "color": "blue" - }, - "cardStyleOption": { - "filled": "填滿", - "outline": "外框", - "subtle": "細微" - }, - "layoutOption": { - "list": "清單", - "grid": "網格" - }, - "sizeOption": { - "sm": "小", - "md": "中", - "lg": "大", - "xl": "特大" - }, - "labelPositionOption": { - "above": "上方", - "below": "下方" - }, - "fieldset": { - "general": "一般", - "connection": "API 連線", - "display": "顯示設定" - }, - "displayTypeDescription": { - "singleValue": "顯示一個帶有標籤和單位的擷取值", - "keyValue": "並排顯示多個帶有標籤的值", - "table": "以表格格式顯示資料列", - "statGrid": "以網格形式顯示彩色統計卡 — 類似 Pi-Hole 或 Speedtest 小工具", - "progressBars": "顯示使用量或完成度的進度條 — 適用於磁碟、記憶體、配額", - "statusIndicator": "彩色狀態點顯示線上/離線或健康狀態", - "countGrid": "在緊湊的網格中顯示精簡的數字 + 標籤計數器", - "raw": "用於偵錯的美化 JSON 輸出", - "actionButton": "點擊時觸發請求的按鈕", - "customJsx": "使用白名單 Mantine 組件的自訂 JSX 佈局,具有完整的 API 資料綁定" - }, - "method": { - "GET": "GET", - "POST": "POST", - "PUT": "PUT", - "DELETE": "DELETE", - "PATCH": "PATCH" - }, - "authType": { - "none": "無", - "bearer": "Bearer 令牌", - "basic": "基本驗證", - "apiKeyHeader": "API 金鑰 (標頭)", - "apiKeyQuery": "API 金鑰 (查詢)" - }, - "displayType": { - "singleValue": "單一值", - "keyValue": "鍵值", - "table": "表格", - "statGrid": "統計網格", - "progressBars": "進度條", - "statusIndicator": "狀態指示器", - "countGrid": "計數網格", - "raw": "原始 JSON", - "actionButton": "動作按鈕", - "customJsx": "自訂 JSX" - }, - "secret": { - "apiKey": "API 金鑰 / 令牌", - "username": "使用者名稱", - "password": "密碼", - "savedPlaceholder": "••••••• (已儲存,留空則保持不變)" - }, - "preview": { - "title": "預覽", - "test": "測試", - "hint": "點擊「測試」以用目前設定預覽 API 回應。", - "rawResponse": "原始 JSON 回應" - }, - "notification": { - "created": "小工具 \"{name}\" 建立成功。", - "updated": "小工具 \"{name}\" 更新成功。", - "deleted": "小工具 \"{name}\" 已刪除。", - "imported": "小工具匯入成功。", - "aiPromptCopied": "AI 提示已複製到剪貼簿", - "aiPromptDescription": "複製預先構建的提示,貼到任何 AI 聊天機器人 (ChatGPT、Claude、Gemini...)。其中包含完整的小工具綱要和您的 API 回應,讓 AI 能為您產生可直接匯入的 JSON 設定。", - "aiPromptCopy": "複製到剪貼簿", - "aiPromptNoResponse": "提示: 先執行測試將您的 API 回應包含在提示中,以獲得更好的結果。", - "aiPromptCopyError": "無法將提示複製到剪貼簿。您的瀏覽器可能不支援此功能。", - "createError": "建立小工具失敗。請檢查 API 端點是否可達。", - "updateError": "更新小工具失敗。您的變更未被儲存。", - "importError": "匯入小工具失敗。請確保檔案是有效的自訂小工具 JSON 匯出。", - "exportError": "匯出小工具失敗。", - "duplicated": "小工具 \"{name}\" 已複製。", - "duplicateError": "複製小工具失敗。", - "toggleError": "切換小工具狀態失敗。", - "deleteError": "刪除小工具失敗。", - "previewError": "無法取得預覽。請檢查網址並重試。", - "executed": "動作執行成功。", - "executeError": "動作失敗: {error}" - }, - "table": { - "name": "名稱", - "url": "網址", - "display": "顯示" - }, - "widget": { - "disabled": "此小工具已停用" - } - }, "integration": { "page": { "list": { @@ -2828,193 +2623,6 @@ "internalServerError": "無法取得 Paperless-ngx 資料" } }, - "patchmon": { - "name": "PatchMon", - "description": "來自 PatchMon 的主機修補狀態概覽", - "title": "PatchMon 統計", - "totalHosts": "主機總數", - "hostsNeedingUpdates": "需要更新", - "securityUpdates": "安全性更新", - "upToDateHosts": "已更新至最新", - "hostsWithSecurityUpdates": "有安全性更新的主機", - "recentUpdates24h": "更新 (24h)", - "totalOutdatedPackages": "過時套件", - "totalRepos": "儲存庫", - "osDistribution": "作業系統分佈", - "compliance": "修補合規性", - "complianceRatio": "{upToDate} / {total}", - "lastUpdated": "更新於 {time}", - "option": { - "showTotalHosts": { - "label": "顯示主機總數", - "description": "顯示受監控的主機總數" - }, - "showHostsNeedingUpdates": { - "label": "顯示需要更新的主機", - "description": "顯示至少有一個過時套件的主機" - }, - "showSecurityUpdates": { - "label": "顯示安全性更新總數", - "description": "顯示可用的安全性更新總數" - }, - "showUpToDateHosts": { - "label": "顯示已更新至最新主機", - "description": "顯示沒有任何過時套件的主機" - }, - "showHostsWithSecurityUpdates": { - "label": "顯示有安全性更新的主機", - "description": "顯示需要安全性修補的主機" - }, - "showRecentUpdates24h": { - "label": "顯示近期更新 (24h)", - "description": "顯示過去 24 小時內已套用的更新數量" - }, - "showTotalOutdatedPackages": { - "label": "顯示過時套件總數", - "description": "顯示所有主機上過時套件的總數" - }, - "showTotalRepos": { - "label": "顯示儲存庫數量", - "description": "顯示正在監控的活躍儲存庫數量" - }, - "enableThresholdColors": { - "label": "啟用閾值顏色", - "description": "根據嚴重性預設將統計值著色為綠色、黃色或紅色" - }, - "useCustomThresholds": { - "label": "進階閾值", - "description": "使用絕對計數或主機總數百分比,對每個統計值自訂警告和嚴重閾值" - }, - "thresholdMode": { - "option": { - "absolute": "絕對計數", - "percent": "主機總數百分比" - } - }, - "hostsNeedingUpdatesThresholdMode": { - "label": "需要更新閾值模式", - "description": "以絕對值或主機總數百分比比較需要更新的計數" - }, - "hostsNeedingUpdatesWarningAt": { - "label": "需要更新警告閾值", - "description": "數值達到此閾值時轉為黃色" - }, - "hostsNeedingUpdatesCriticalAt": { - "label": "需要更新嚴重閾值", - "description": "數值達到此閾值時轉為紅色" - }, - "securityUpdatesThresholdMode": { - "label": "安全性更新閾值模式", - "description": "以絕對值或主機總數百分比比較安全性更新的計數" - }, - "securityUpdatesWarningAt": { - "label": "安全性更新警告閾值", - "description": "數值達到此閾值時轉為黃色" - }, - "securityUpdatesCriticalAt": { - "label": "安全性更新嚴重閾值", - "description": "數值達到此閾值時轉為紅色" - }, - "hostsWithSecurityUpdatesThresholdMode": { - "label": "有安全性更新主機閾值模式", - "description": "以絕對值或主機總數百分比比較主機計數" - }, - "hostsWithSecurityUpdatesWarningAt": { - "label": "有安全性更新主機警告閾值", - "description": "數值達到此閾值時轉為黃色" - }, - "hostsWithSecurityUpdatesCriticalAt": { - "label": "有安全性更新主機嚴重閾值", - "description": "數值達到此閾值時轉為紅色" - }, - "upToDateHostsThresholdMode": { - "label": "已更新至最新主機閾值模式", - "description": "以絕對值或主機總數百分比比較已更新至最新主機計數" - }, - "upToDateHostsWarningAt": { - "label": "已更新至最新主機警告閾值", - "description": "數值達到或高於此閾值但低於全覆蓋時轉為黃色" - }, - "upToDateHostsCriticalAt": { - "label": "已更新至最新主機嚴重閾值", - "description": "數值低於此閾值時轉為紅色" - }, - "totalOutdatedPackagesThresholdMode": { - "label": "過時套件閾值模式", - "description": "以絕對值或主機總數百分比比較過時套件計數" - }, - "totalOutdatedPackagesWarningAt": { - "label": "過時套件警告閾值", - "description": "數值達到此閾值時轉為黃色" - }, - "totalOutdatedPackagesCriticalAt": { - "label": "過時套件嚴重閾值", - "description": "數值達到此閾值時轉為紅色" - }, - "showOsDistribution": { - "label": "顯示作業系統分佈", - "description": "顯示按作業系統細分的受監控主機" - }, - "osDistributionLimit": { - "label": "作業系統分佈限制", - "description": "最多顯示的作業系統數量", - "option": { - "3": "前 3 名", - "5": "前 5 名", - "10": "前 10 名", - "all": "全部" - } - }, - "showOsVersion": { - "label": "顯示作業系統版本", - "description": "當可用時,在每個分佈標籤後附加作業系統版本" - }, - "showComplianceHero": { - "label": "顯示合規性英雄", - "description": "顯示一個合規性環,展示已更新至最新主機的百分比" - }, - "osDisplayMode": { - "label": "作業系統顯示模式", - "description": "選擇如何顯示作業系統分佈", - "option": { - "bars": "水平長條", - "donut": "甜甜圈圖" - } - } - }, - "error": { - "internalServerError": "無法擷取 PatchMon 資料" - } - }, - "bazarr": { - "name": "Bazarr", - "description": "來自 Bazarr 實例的缺少字幕和健康狀態概覽", - "episodes": "缺少的集數", - "movies": "缺少的電影", - "providers": "提供者問題", - "status": "健康問題", - "option": { - "showMissingEpisodes": { - "label": "顯示缺少的集數", - "description": "顯示缺少字幕的集數數量" - }, - "showMissingMovies": { - "label": "顯示缺少的電影", - "description": "顯示缺少字幕的電影數量" - }, - "showProviderIssues": { - "label": "顯示提供者問題", - "description": "顯示有問題的字幕提供者數量" - }, - "showHealthIssues": { - "label": "顯示健康問題", - "description": "顯示 Bazarr 健康問題的數量" - } - }, - "error": { - "internalServerError": "無法擷取 Bazarr 資料" - } - }, "immich-serverStats": { "name": "", "description": "", @@ -3387,35 +2995,6 @@ } } }, - "mediaMissing": { - "name": "缺少和佇列中的媒體", - "description": "顯示來自 Radarr 和 Sonarr 的缺少和佇列中的電影及影集", - "option": { - "showMissing": { - "label": "顯示缺少的項目" - }, - "showQueued": { - "label": "顯示佇列中的項目" - }, - "pageSize": { - "label": "每頁項目數" - } - }, - "tab": { - "missing": "缺少", - "queued": "佇列中" - }, - "type": { - "movie": "電影", - "episode": "集數" - }, - "empty": { - "missing": "沒有缺少的項目", - "queued": "沒有佇列中的項目", - "noTabsEnabled": "在小工具設定中至少啟用一個分頁" - }, - "timeLeft": "剩餘時間" - }, "rssFeed": { "name": "RSS 訂閱", "description": "顯示一個或多個 RSS、ATOM、JSON 源", @@ -3744,40 +3323,6 @@ "internalServerError": "無法取得運作時間資料" } }, - "traefik": { - "name": "Traefik", - "description": "Traefik 路由器、服務、中間件和入口點概覽", - "option": { - "showTcp": { - "label": "顯示 TCP" - }, - "showUdp": { - "label": "顯示 UDP" - }, - "showEntryPoints": { - "label": "顯示入口點" - } - }, - "instances": "Traefik 實例", - "versionUnknown": "版本未知", - "summary": { - "routers": "路由器", - "entryPoints": "入口點" - }, - "resource": { - "routers": "路由器", - "services": "服務", - "middlewares": "中間件" - }, - "status": { - "healthy": "健康", - "errors": "{count} 個錯誤", - "warnings": "{count} 個警告" - }, - "error": { - "internalServerError": "無法擷取 Traefik 資料" - } - }, "audioStats": { "name": "音訊統計", "description": "來自 Navidrome 或 Audiobookshelf 的資料庫和播放統計資料", @@ -3901,26 +3446,6 @@ "unhealthy": "" } }, - "customApi": { - "name": "自訂 API", - "description": "使用自訂設定顯示來自任何外部 API 的資料。", - "option": { - "definitionId": { - "label": "定義 ID" - }, - "refreshInterval": { - "label": "重新整理間隔", - "description": "從 API 重新擷取資料的頻率 (秒)" - } - }, - "noDefinition": "未選擇定義", - "definitionNotFound": "找不到小工具定義。可能已被刪除。", - "noDisplayOutput": "無顯示輸出", - "executeConfirm": "確定要執行此動作嗎?", - "executing": "正在執行……", - "executeSuccess": "動作執行成功", - "executeFailed": "動作失敗。請檢查小工具設定。" - }, "beszelSystemTable": { "name": "Beszel 系統(表格)", "description": "所有 Beszel 監控系統的表格檢視,帶有可排序的欄位和狀態指示器", @@ -4171,6 +3696,256 @@ "subtitle": "Docker 容器的網路流量" } } + }, + "patchmon": { + "name": "PatchMon", + "description": "來自 PatchMon 的主機修補狀態概覽", + "title": "PatchMon 統計", + "totalHosts": "主機總數", + "hostsNeedingUpdates": "需要更新", + "securityUpdates": "安全性更新", + "upToDateHosts": "已更新至最新", + "hostsWithSecurityUpdates": "有安全性更新的主機", + "recentUpdates24h": "更新 (24h)", + "totalOutdatedPackages": "過時套件", + "totalRepos": "儲存庫", + "osDistribution": "作業系統分佈", + "compliance": "修補合規性", + "complianceRatio": "{upToDate} / {total}", + "lastUpdated": "更新於 {time}", + "option": { + "showTotalHosts": { + "label": "顯示主機總數", + "description": "顯示受監控的主機總數" + }, + "showHostsNeedingUpdates": { + "label": "顯示需要更新的主機", + "description": "顯示至少有一個過時套件的主機" + }, + "showSecurityUpdates": { + "label": "顯示安全性更新總數", + "description": "顯示可用的安全性更新總數" + }, + "showUpToDateHosts": { + "label": "顯示已更新至最新主機", + "description": "顯示沒有任何過時套件的主機" + }, + "showHostsWithSecurityUpdates": { + "label": "顯示有安全性更新的主機", + "description": "顯示需要安全性修補的主機" + }, + "showRecentUpdates24h": { + "label": "顯示近期更新 (24h)", + "description": "顯示過去 24 小時內已套用的更新數量" + }, + "showTotalOutdatedPackages": { + "label": "顯示過時套件總數", + "description": "顯示所有主機上過時套件的總數" + }, + "showTotalRepos": { + "label": "顯示儲存庫數量", + "description": "顯示正在監控的活躍儲存庫數量" + }, + "enableThresholdColors": { + "label": "啟用閾值顏色", + "description": "根據嚴重性預設將統計值著色為綠色、黃色或紅色" + }, + "useCustomThresholds": { + "label": "進階閾值", + "description": "使用絕對計數或主機總數百分比,對每個統計值自訂警告和嚴重閾值" + }, + "thresholdMode": { + "option": { + "absolute": "絕對計數", + "percent": "主機總數百分比" + } + }, + "hostsNeedingUpdatesThresholdMode": { + "label": "需要更新閾值模式", + "description": "以絕對值或主機總數百分比比較需要更新的計數" + }, + "hostsNeedingUpdatesWarningAt": { + "label": "需要更新警告閾值", + "description": "數值達到此閾值時轉為黃色" + }, + "hostsNeedingUpdatesCriticalAt": { + "label": "需要更新嚴重閾值", + "description": "數值達到此閾值時轉為紅色" + }, + "securityUpdatesThresholdMode": { + "label": "安全性更新閾值模式", + "description": "以絕對值或主機總數百分比比較安全性更新的計數" + }, + "securityUpdatesWarningAt": { + "label": "安全性更新警告閾值", + "description": "數值達到此閾值時轉為黃色" + }, + "securityUpdatesCriticalAt": { + "label": "安全性更新嚴重閾值", + "description": "數值達到此閾值時轉為紅色" + }, + "hostsWithSecurityUpdatesThresholdMode": { + "label": "有安全性更新主機閾值模式", + "description": "以絕對值或主機總數百分比比較主機計數" + }, + "hostsWithSecurityUpdatesWarningAt": { + "label": "有安全性更新主機警告閾值", + "description": "數值達到此閾值時轉為黃色" + }, + "hostsWithSecurityUpdatesCriticalAt": { + "label": "有安全性更新主機嚴重閾值", + "description": "數值達到此閾值時轉為紅色" + }, + "upToDateHostsThresholdMode": { + "label": "已更新至最新主機閾值模式", + "description": "以絕對值或主機總數百分比比較已更新至最新主機計數" + }, + "upToDateHostsWarningAt": { + "label": "已更新至最新主機警告閾值", + "description": "數值達到或高於此閾值但低於全覆蓋時轉為黃色" + }, + "upToDateHostsCriticalAt": { + "label": "已更新至最新主機嚴重閾值", + "description": "數值低於此閾值時轉為紅色" + }, + "totalOutdatedPackagesThresholdMode": { + "label": "過時套件閾值模式", + "description": "以絕對值或主機總數百分比比較過時套件計數" + }, + "totalOutdatedPackagesWarningAt": { + "label": "過時套件警告閾值", + "description": "數值達到此閾值時轉為黃色" + }, + "totalOutdatedPackagesCriticalAt": { + "label": "過時套件嚴重閾值", + "description": "數值達到此閾值時轉為紅色" + }, + "showOsDistribution": { + "label": "顯示作業系統分佈", + "description": "顯示按作業系統細分的受監控主機" + }, + "osDistributionLimit": { + "label": "作業系統分佈限制", + "description": "最多顯示的作業系統數量", + "option": { + "3": "前 3 名", + "5": "前 5 名", + "10": "前 10 名", + "all": "全部" + } + }, + "showOsVersion": { + "label": "顯示作業系統版本", + "description": "當可用時,在每個分佈標籤後附加作業系統版本" + }, + "showComplianceHero": { + "label": "顯示合規性英雄", + "description": "顯示一個合規性環,展示已更新至最新主機的百分比" + }, + "osDisplayMode": { + "label": "作業系統顯示模式", + "description": "選擇如何顯示作業系統分佈", + "option": { + "bars": "水平長條", + "donut": "甜甜圈圖" + } + } + }, + "error": { + "internalServerError": "無法擷取 PatchMon 資料" + } + }, + "bazarr": { + "name": "Bazarr", + "description": "來自 Bazarr 實例的缺少字幕和健康狀態概覽", + "episodes": "缺少的集數", + "movies": "缺少的電影", + "providers": "提供者問題", + "status": "健康問題", + "option": { + "showMissingEpisodes": { + "label": "顯示缺少的集數", + "description": "顯示缺少字幕的集數數量" + }, + "showMissingMovies": { + "label": "顯示缺少的電影", + "description": "顯示缺少字幕的電影數量" + }, + "showProviderIssues": { + "label": "顯示提供者問題", + "description": "顯示有問題的字幕提供者數量" + }, + "showHealthIssues": { + "label": "顯示健康問題", + "description": "顯示 Bazarr 健康問題的數量" + } + }, + "error": { + "internalServerError": "無法擷取 Bazarr 資料" + } + }, + "mediaMissing": { + "name": "缺少和佇列中的媒體", + "description": "顯示來自 Radarr 和 Sonarr 的缺少和佇列中的電影及影集", + "option": { + "showMissing": { + "label": "顯示缺少的項目" + }, + "showQueued": { + "label": "顯示佇列中的項目" + }, + "pageSize": { + "label": "每頁項目數" + } + }, + "tab": { + "missing": "缺少", + "queued": "佇列中" + }, + "type": { + "movie": "電影", + "episode": "集數" + }, + "empty": { + "missing": "沒有缺少的項目", + "queued": "沒有佇列中的項目", + "noTabsEnabled": "在小工具設定中至少啟用一個分頁" + }, + "timeLeft": "剩餘時間" + }, + "traefik": { + "name": "Traefik", + "description": "Traefik 路由器、服務、中間件和入口點概覽", + "option": { + "showTcp": { + "label": "顯示 TCP" + }, + "showUdp": { + "label": "顯示 UDP" + }, + "showEntryPoints": { + "label": "顯示入口點" + } + }, + "instances": "Traefik 實例", + "versionUnknown": "版本未知", + "summary": { + "routers": "路由器", + "entryPoints": "入口點" + }, + "resource": { + "routers": "路由器", + "services": "服務", + "middlewares": "中間件" + }, + "status": { + "healthy": "健康", + "errors": "{count} 個錯誤", + "warnings": "{count} 個警告" + }, + "error": { + "internalServerError": "無法擷取 Traefik 資料" + } } }, "widgetPreview": { @@ -4551,11 +4326,11 @@ }, "navbar": { "items": { + "workshop": "Workshop", "home": "首頁", "boards": "面板", "apps": "應用程式", "integrations": "集成", - "customWidgets": "自訂小工具", "searchEngies": "搜尋引擎", "medias": "多媒體", "users": { @@ -5694,6 +5469,9 @@ }, "navigationStructure": { "manage": { + "workshop": { + "label": "Workshop" + }, "label": "管理", "boards": { "label": "面板" @@ -5728,18 +5506,6 @@ "label": "編輯" } }, - "custom-widgets": { - "label": "自訂小工具", - "new": { - "label": "新增" - }, - "edit": { - "label": "編輯", - "flow": { - "label": "流程" - } - } - }, "users": { "label": "使用者", "create": { diff --git a/packages/widgets/src/app/component.tsx b/packages/widgets/src/app/component.tsx index b05134294..8475de4e0 100644 --- a/packages/widgets/src/app/component.tsx +++ b/packages/widgets/src/app/component.tsx @@ -116,7 +116,10 @@ export default function AppWidget({ options, isEditMode, height, width }: Widget /> - {options.pingEnabled && !settings.forceDisableStatus && !board.disableStatus && app.href ? ( + {options.pingEnabled && + !settings.forceDisableStatus && + !board.disableStatus && + Boolean(app.pingUrl ?? app.href) ? ( }> diff --git a/packages/widgets/src/beszel-alerts/component.tsx b/packages/widgets/src/beszel-alerts/component.tsx index 23243f35e..8990767f3 100644 --- a/packages/widgets/src/beszel-alerts/component.tsx +++ b/packages/widgets/src/beszel-alerts/component.tsx @@ -16,6 +16,7 @@ import { VisuallyHidden, } from "@mantine/core"; import { IconBellOff, IconCircleCheck, IconFlame, IconHistory } from "@tabler/icons-react"; +import { getQueryKey } from "@trpc/react-query"; import dayjs from "dayjs"; import relativeTime from "dayjs/plugin/relativeTime"; import type { LucideIcon } from "lucide-react"; @@ -27,6 +28,10 @@ import { useScopedI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; import { getUsableWidgetQueryData } from "../common/query-state"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; +import { useWidgetRuntimeQueries } from "../runtime-hooks"; +import { getBeszelAlertsQueryInput } from "./display"; +import { buildBeszelSystemNameMap, getBeszelSystemName } from "./system-name-map"; const alertIconMap: Record = { CPU: Cpu, @@ -50,43 +55,64 @@ export default function BeszelAlertsWidget({ integrationIds, isEditMode, height, + displayMode, + widgetRuntimeRef, }: WidgetComponentProps<"beszelAlerts">) { const t = useScopedI18n("widget.beszelAlerts"); + const isAdvanced = displayMode === "advanced"; const alertsInput = useMemo( - () => ({ integrationIds, includeHistory: options.showHistory, maxHistoryItems: options.maxHistoryItems }), - [integrationIds, options.showHistory, options.maxHistoryItems], + () => + getBeszelAlertsQueryInput( + integrationIds, + { showHistory: options.showHistory, maxHistoryItems: options.maxHistoryItems }, + isAdvanced, + ), + [integrationIds, options.showHistory, options.maxHistoryItems, isAdvanced], ); const alertsQuery = clientApi.widget.beszel.getAlerts.useQuery(alertsInput); - const results = getUsableWidgetQueryData(alertsQuery) ?? []; + const runtimeQueries = useMemo( + () => [getQueryKey(clientApi.widget.beszel.getAlerts, alertsInput, "query")], + [alertsInput], + ); + useWidgetRuntimeQueries(widgetRuntimeRef, runtimeQueries); + const resultData = getUsableWidgetQueryData(alertsQuery); + const results = useMemo(() => resultData ?? [], [resultData]); const { isPending } = alertsQuery; - const systemNameMap = useMemo(() => { - const map: Record = {}; - for (const r of results) { - if (r.systemNameMap) { - Object.assign(map, r.systemNameMap); - } - } - return map; - }, [results]); + const systemNameMap = useMemo(() => buildBeszelSystemNameMap(results), [results]); + const showIntegrationName = isAdvanced || results.length > 1; const alerts = useMemo( - () => results.flatMap((r) => r.alerts.map((a) => ({ ...a, _key: `${r.integrationId}:${a.id}` }))), + () => + results.flatMap((r) => + r.alerts.map((a) => ({ + ...a, + integrationId: r.integrationId, + integrationName: r.integrationName, + key: `${r.integrationId}:${a.id}`, + })), + ), [results], ); const history = useMemo(() => { - const all = results.flatMap((r) => r.history.map((h) => ({ ...h, _key: `${r.integrationId}:${h.id}` }))); - return all - .toSorted((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime()) - .slice(0, options.maxHistoryItems); - }, [results, options.maxHistoryItems]); + const all = results.flatMap((r) => + r.history.map((h) => ({ + ...h, + integrationId: r.integrationId, + integrationName: r.integrationName, + key: `${r.integrationId}:${h.id}`, + })), + ); + const sorted = all.toSorted((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime()); + return isAdvanced ? sorted : sorted.slice(0, options.maxHistoryItems); + }, [results, options.maxHistoryItems, isAdvanced]); const triggeredAlerts = alerts.filter((a) => a.triggered); const okAlerts = alerts.filter((a) => !a.triggered); - const showOkAlerts = triggeredAlerts.length === 0 || height >= 260; - const showHistory = options.showHistory && height >= 360; - const showAlertDescriptions = height >= 190; + const showOkAlerts = isAdvanced || triggeredAlerts.length === 0 || height >= 260; + const showHistory = isAdvanced || (options.showHistory && height >= 360); + const showAlertDescriptions = isAdvanced || height >= 190; if (isPending) { return ( @@ -99,7 +125,10 @@ export default function BeszelAlertsWidget({ return ( - + + + + @@ -124,11 +153,12 @@ export default function BeszelAlertsWidget({ {triggeredAlerts.map((alert) => ( @@ -148,11 +178,12 @@ export default function BeszelAlertsWidget({ {okAlerts.map((alert) => ( @@ -171,11 +202,12 @@ export default function BeszelAlertsWidget({ {history.map((entry) => { - const systemName = systemNameMap[entry.system] ?? entry.system; + const systemName = getBeszelSystemName(systemNameMap, entry.integrationId, entry.system); + const systemLabel = showIntegrationName ? `${systemName} · ${entry.integrationName}` : systemName; const isResolved = !!entry.resolved; const HistoryIcon = alertIconMap[entry.name] ?? Server; return ( - + - {systemName} + {systemLabel} @@ -218,6 +250,7 @@ interface AlertRowProps { value: number; min: number; systemName: string; + integrationName?: string; triggered: boolean; showDescription: boolean; } @@ -243,7 +276,7 @@ function formatAlertDescription(name: string, value: number, min: number): strin return `exceeds ${value}${suffix} over ${min} min`; } -function AlertRow({ name, value, min, systemName, triggered, showDescription }: AlertRowProps) { +function AlertRow({ name, value, min, systemName, integrationName, triggered, showDescription }: AlertRowProps) { const Icon = alertIconMap[name] ?? Server; const description = formatAlertDescription(name, value, min); return ( @@ -263,7 +296,7 @@ function AlertRow({ name, value, min, systemName, triggered, showDescription }: - {systemName} + {integrationName ? `${systemName} · ${integrationName}` : systemName} · diff --git a/packages/widgets/src/beszel-alerts/index.ts b/packages/widgets/src/beszel-alerts/index.ts index db1e791b2..e8a32796d 100644 --- a/packages/widgets/src/beszel-alerts/index.ts +++ b/packages/widgets/src/beszel-alerts/index.ts @@ -1,19 +1,22 @@ import { IconBell, IconServerOff } from "@tabler/icons-react"; import { z } from "zod/v4"; -import { createWidgetDefinition, widgetQueryInputMatches } from "../definition"; +import { createWidgetDefinition, matchesWidgetRuntimeQuery, widgetQueryInputMatches } from "../definition"; import { optionsBuilder } from "../options"; export const { definition, componentLoader } = createWidgetDefinition("beszelAlerts", { icon: IconBell, - supportsAdvancedFocus: false, queryKey: [["widget", "beszel", "getAlerts"]], - queryMatcher: ({ input }, scope) => - widgetQueryInputMatches(input, { + queryMatcher(query, scope) { + const hasRuntimeAlertsQuery = scope.runtimeQueries.some(({ path }) => path.at(-1) === "getAlerts"); + if (hasRuntimeAlertsQuery) return matchesWidgetRuntimeQuery(query, scope); + + return widgetQueryInputMatches(query.input, { integrationIds: scope.integrationIds, includeHistory: scope.options.showHistory, maxHistoryItems: scope.options.maxHistoryItems, - }), + }); + }, supportedIntegrations: ["beszel", "mock"], integrationsRequired: true, createOptions() { diff --git a/packages/widgets/src/beszel-system-grid/component.tsx b/packages/widgets/src/beszel-system-grid/component.tsx index 66f32dc35..84f796fe2 100644 --- a/packages/widgets/src/beszel-system-grid/component.tsx +++ b/packages/widgets/src/beszel-system-grid/component.tsx @@ -1,7 +1,7 @@ "use client"; import type { MantineSize } from "@mantine/core"; -import { Badge, Box, Card, Center, Group, Loader, Progress, Text, Stack } from "@mantine/core"; +import { Badge, Box, Card, Center, Group, Loader, Progress, SimpleGrid, Stack, Text } from "@mantine/core"; import { Activity, Battery, @@ -19,6 +19,7 @@ import { IconServerOff } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { useRequiredBoard } from "@homarr/boards/context"; +import { formatBytes } from "@homarr/common"; import { useModalAction } from "@homarr/modals"; import { useScopedI18n } from "@homarr/translation/client"; @@ -38,8 +39,10 @@ import { import { useBeszelFilteredSystems } from "../beszel/_shared/hooks"; import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; import { getUsableWidgetQueryData } from "../common/query-state"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; import { BeszelSystemStatsModal } from "../beszel/_shared/system-stats-modal"; import { DiskUsage } from "../beszel/_shared/disk-usage"; +import { isBeszelGridMetricVisible } from "./display"; interface SizeConfig { iconSize: number; @@ -117,10 +120,12 @@ const getMaxVisibleMetrics = (cellHeight: number, size: SizeConfig): number => { const MIN_CELL_WIDTH = 140; const MIN_CELL_HEIGHT = 80; +const ADVANCED_MIN_CELL_WIDTH = 320; +const ADVANCED_MIN_CELL_HEIGHT = 420; -const getColCount = (width: number, _height: number, itemCount: number): number => { +const getColCount = (width: number, _height: number, itemCount: number, minCellWidth = MIN_CELL_WIDTH): number => { if (itemCount <= 1) return 1; - const maxCols = Math.min(itemCount, Math.max(1, Math.floor(width / MIN_CELL_WIDTH))); + const maxCols = Math.min(itemCount, Math.max(1, Math.floor(width / minCellWidth))); let best = 1; for (let c = 1; c <= maxCols; c++) { @@ -168,12 +173,14 @@ const MetricRow = ({ icon, label, value, progress, size }: MetricRowProps) => ( ); interface SystemCardProps { - system: BeszelSystemRow & { _key: string }; + system: BeszelSystemRow & { rowKey: string }; options: WidgetComponentProps<"beszelSystemGrid">["options"]; t: ReturnType>; size: SizeConfig; maxMetrics: number; itemRadius: MantineSize; + integrationName: string; + isAdvanced: boolean; onClick?: () => void; } @@ -190,7 +197,8 @@ const metricRenderers = [ size={sz} /> ), - visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showCpu, + visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) => + isBeszelGridMetricVisible(o.showCpu, advanced), }, { key: "showMemory", @@ -204,7 +212,8 @@ const metricRenderers = [ size={sz} /> ), - visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showMemory, + visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) => + isBeszelGridMetricVisible(o.showMemory, advanced), }, { key: "showDisk", @@ -217,7 +226,8 @@ const metricRenderers = [ ), - visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showDisk, + visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) => + isBeszelGridMetricVisible(o.showDisk, advanced), }, { key: "showGpu", @@ -231,7 +241,8 @@ const metricRenderers = [ size={sz} /> ), - visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showGpu && s.gpu > 0, + visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) => + isBeszelGridMetricVisible(o.showGpu, advanced, s.gpu > 0), }, { key: "showLoadAvg", @@ -244,7 +255,8 @@ const metricRenderers = [ size={sz} /> ), - visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showLoadAvg && s.loadAvg !== null, + visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) => + isBeszelGridMetricVisible(o.showLoadAvg, advanced, s.loadAvg !== null), }, { key: "showNet", @@ -257,7 +269,8 @@ const metricRenderers = [ size={sz} /> ), - visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showNet, + visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) => + isBeszelGridMetricVisible(o.showNet, advanced), }, { key: "showTemp", @@ -270,7 +283,8 @@ const metricRenderers = [ size={sz} /> ), - visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showTemp && s.temp !== null, + visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) => + isBeszelGridMetricVisible(o.showTemp, advanced, s.temp !== null), }, { key: "showBattery", @@ -287,7 +301,8 @@ const metricRenderers = [ /> ); }, - visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showBattery && s.battery !== null, + visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) => + isBeszelGridMetricVisible(o.showBattery, advanced, s.battery !== null), }, { key: "showServices", @@ -300,7 +315,8 @@ const metricRenderers = [ size={sz} /> ), - visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showServices, + visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) => + isBeszelGridMetricVisible(o.showServices, advanced), }, { key: "showUptime", @@ -313,7 +329,8 @@ const metricRenderers = [ size={sz} /> ), - visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showUptime, + visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) => + isBeszelGridMetricVisible(o.showUptime, advanced), }, { key: "showAgent", @@ -326,12 +343,23 @@ const metricRenderers = [ size={sz} /> ), - visible: (s: BeszelSystemRow, o: SystemCardProps["options"]) => o.showAgent, + visible: (s: BeszelSystemRow, o: SystemCardProps["options"], advanced: boolean) => + isBeszelGridMetricVisible(o.showAgent, advanced), }, ] as const; -const SystemCard = ({ system, options, t, size, maxMetrics, itemRadius, onClick }: SystemCardProps) => { - const enabledMetrics = metricRenderers.filter((metric) => metric.visible(system, options)); +const SystemCard = ({ + system, + options, + t, + size, + maxMetrics, + itemRadius, + integrationName, + isAdvanced, + onClick, +}: SystemCardProps) => { + const enabledMetrics = metricRenderers.filter((metric) => metric.visible(system, options, isAdvanced)); const visibleMetrics = enabledMetrics.slice(0, maxMetrics); const hiddenMetricCount = enabledMetrics.length - visibleMetrics.length; @@ -368,6 +396,20 @@ const SystemCard = ({ system, options, t, size, maxMetrics, itemRadius, onClick + {isAdvanced && ( + + + + + + 0 ? formatBytes(system.memoryTotal) : "—"} + /> + + + )} + {visibleMetrics.map((m) => m.render(system, t, size))} @@ -380,12 +422,24 @@ const SystemCard = ({ system, options, t, size, maxMetrics, itemRadius, onClick ); }; +const SystemMetadata = ({ label, value }: { label: string; value: string }) => ( + + + {label} + + + {value} + + +); + export default function BeszelSystemGridWidget({ options, integrationIds, isEditMode, width, height, + displayMode, }: WidgetComponentProps<"beszelSystemGrid">) { const t = useScopedI18n("widget.beszelSystemGrid"); const board = useRequiredBoard(); @@ -394,6 +448,8 @@ export default function BeszelSystemGridWidget({ const systemsQuery = clientApi.widget.beszel.getSystems.useQuery({ integrationIds }); const results = getUsableWidgetQueryData(systemsQuery) ?? []; const { isPending } = systemsQuery; + const isAdvanced = displayMode === "advanced"; + const integrationNames = new Map(results.map((result) => [result.integrationId, result.integrationName])); const filteredSystems = useBeszelFilteredSystems(results, options.statusFilter); @@ -408,7 +464,10 @@ export default function BeszelSystemGridWidget({ if (filteredSystems.length === 0) { return ( - + + + +
    @@ -421,19 +480,23 @@ export default function BeszelSystemGridWidget({ ); } - const cols = getColCount(width, height, filteredSystems.length); + const minimumCellWidth = isAdvanced ? ADVANCED_MIN_CELL_WIDTH : MIN_CELL_WIDTH; + const cols = getColCount(width, height, filteredSystems.length, minimumCellWidth); const rows = Math.ceil(filteredSystems.length / cols) || 1; const rawCellHeight = height / rows; - const minimumCellHeight = MIN_CELL_HEIGHT; + const minimumCellHeight = isAdvanced ? ADVANCED_MIN_CELL_HEIGHT : MIN_CELL_HEIGHT; const scrollEnabled = rawCellHeight < minimumCellHeight; const effectiveCellHeight = scrollEnabled ? minimumCellHeight : rawCellHeight; const cellWidth = width / cols; const size = getSizeConfig(cellWidth, effectiveCellHeight); - const maxMetrics = getMaxVisibleMetrics(effectiveCellHeight, size); + const maxMetrics = isAdvanced ? Number.POSITIVE_INFINITY : getMaxVisibleMetrics(effectiveCellHeight, size); return ( - + + + + {filteredSystems.map((system) => { - const integrationId = system._key.split(":")[0] ?? ""; + const integrationId = system.rowKey.split(":")[0] ?? ""; + const integrationName = integrationNames.get(integrationId) ?? "—"; const handleClick = isEditMode ? undefined : () => openModal({ integrationId, systemId: system.id }, { title: system.name }); return ( ); diff --git a/packages/widgets/src/beszel-system-grid/index.ts b/packages/widgets/src/beszel-system-grid/index.ts index b3ef14806..9a5444e28 100644 --- a/packages/widgets/src/beszel-system-grid/index.ts +++ b/packages/widgets/src/beszel-system-grid/index.ts @@ -6,7 +6,6 @@ import { optionsBuilder } from "../options"; export const { definition, componentLoader } = createWidgetDefinition("beszelSystemGrid", { icon: IconLayoutGrid, - supportsAdvancedFocus: false, queryKey: [["widget", "beszel", "getSystems"]], supportedIntegrations: ["beszel", "mock"], integrationsRequired: true, diff --git a/packages/widgets/src/beszel-system-stats/component.tsx b/packages/widgets/src/beszel-system-stats/component.tsx index eef65b348..d776af04c 100644 --- a/packages/widgets/src/beszel-system-stats/component.tsx +++ b/packages/widgets/src/beszel-system-stats/component.tsx @@ -19,6 +19,7 @@ import { useWidgetRuntimeQueries } from "../runtime-hooks"; import type { BeszelTimePeriod } from "../beszel/_shared/chart"; import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; import { getUsableWidgetQueryData } from "../common/query-state"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; import { BeszelStatsView } from "../beszel/_shared/stats-view"; import { createBeszelSystemChoices, resolveBeszelSystemChoice } from "./selection"; @@ -46,7 +47,8 @@ export default function BeszelSystemStatsWidget({ }), }); const systemsQuery = clientApi.widget.beszel.getSystems.useQuery({ integrationIds }); - const systemsResult = getUsableWidgetQueryData(systemsQuery) ?? []; + const systemsData = getUsableWidgetQueryData(systemsQuery); + const systemsResult = useMemo(() => systemsData ?? [], [systemsData]); const { isPending: systemsPending } = systemsQuery; const systems = useMemo(() => createBeszelSystemChoices(systemsResult), [systemsResult]); @@ -140,7 +142,10 @@ export default function BeszelSystemStatsWidget({ if (systems.length === 0) { return ( - + + + +
    @@ -177,7 +182,10 @@ export default function BeszelSystemStatsWidget({ return ( - + + + + = { asc: 1, desc: -1 }; -type SystemRowWithKey = BeszelSystemRow & { _key: string }; +type SystemRowWithKey = BeszelSystemRow & { rowKey: string; integrationName: string }; const columnAccessors = [ "name", + "integrationName", + "hostname", + "osName", + "cpuModel", + "cores", + "memoryTotal", "cpu", "memory", "disk", @@ -60,7 +69,7 @@ const columnAccessors = [ "services", "uptime", "agentVersion", -] as const satisfies readonly (keyof BeszelSystemRow)[]; +] as const satisfies readonly (keyof SystemRowWithKey)[]; interface SizeConfig { iconSize: number; @@ -113,6 +122,7 @@ export default function BeszelSystemTableWidget({ boardId, itemId, setOptions, + displayMode, }: WidgetComponentProps<"beszelSystemTable">) { const t = useScopedI18n("widget.beszelSystemTable"); const { openModal } = useModalAction(BeszelSystemStatsModal); @@ -120,26 +130,15 @@ export default function BeszelSystemTableWidget({ const { data: session } = useSession(); const hasChangeAccess = board ? constructBoardPermissions(board, session).hasChangeAccess : false; const systemsQuery = clientApi.widget.beszel.getSystems.useQuery({ integrationIds }); - const results = getUsableWidgetQueryData(systemsQuery) ?? []; + const systemsData = getUsableWidgetQueryData(systemsQuery); + const results = useMemo(() => systemsData ?? [], [systemsData]); const { isPending } = systemsQuery; + const isAdvanced = displayMode === "advanced"; const size = useMemo(() => getSizeConfig(width), [width]); - const visibleMetricKeys = useMemo(() => { - const enabled = [ - "showCpu", - "showMemory", - "showDisk", - "showGpu", - "showLoadAvg", - "showNet", - "showTemp", - "showBattery", - "showServices", - "showUptime", - "showAgent", - ].filter((key) => options[key as keyof typeof options]) as string[]; - const budget = width < 360 ? 1 : width < 560 ? 2 : width < 760 ? 4 : enabled.length; - return new Set(enabled.slice(0, budget)); - }, [options, width]); + const visibleMetricKeys = useMemo( + () => getBeszelTableVisibleMetricKeys(options, width, isAdvanced), + [options, width, isAdvanced], + ); const { mutate: saveItemOptions } = clientApi.widget.options.saveItemOptions.useMutation({ onError: () => @@ -157,6 +156,18 @@ export default function BeszelSystemTableWidget({ }); const filteredSystems = useBeszelFilteredSystems(results, options.statusFilter); + const integrationNames = useMemo( + () => new Map(results.map((result) => [result.integrationId, result.integrationName])), + [results], + ); + const systemsWithSource = useMemo( + () => + filteredSystems.map((system) => ({ + ...system, + integrationName: integrationNames.get(system.rowKey.split(":")[0] ?? "") ?? "—", + })), + [filteredSystems, integrationNames], + ); const [sortStatus, setSortStatus] = useState>({ columnAccessor: options.sortBy, @@ -170,16 +181,16 @@ export default function BeszelSystemTableWidget({ }, [options.sortBy, options.sortDirection]); const sortedSystems = useMemo(() => { - const accessor = sortStatus.columnAccessor as keyof BeszelSystemRow; + const accessor = sortStatus.columnAccessor as keyof SystemRowWithKey; const dir = directionMultiplier[sortStatus.direction] ?? 1; - return [...filteredSystems].toSorted((a, b) => { + return [...systemsWithSource].toSorted((a, b) => { const aVal = a[accessor] ?? 0; const bVal = b[accessor] ?? 0; if (typeof aVal === "string" && typeof bVal === "string") return aVal.localeCompare(bVal) * dir; if (typeof aVal === "number" && typeof bVal === "number") return (aVal - bVal) * dir; return 0; }); - }, [filteredSystems, sortStatus]); + }, [systemsWithSource, sortStatus]); const columns = useMemo((): DataTableColumn[] => { const cols: (DataTableColumn | false)[] = [ @@ -203,6 +214,54 @@ export default function BeszelSystemTableWidget({ ), }, + isAdvanced && { + accessor: "integrationName", + width: 140, + ellipsis: true, + title: t("column.source"), + sortable: true, + render: (record) => {record.integrationName}, + }, + isAdvanced && { + accessor: "hostname", + width: 150, + ellipsis: true, + title: t("column.hostname"), + sortable: true, + render: (record) => {record.hostname || "—"}, + }, + isAdvanced && { + accessor: "osName", + width: 160, + ellipsis: true, + title: t("column.os"), + sortable: true, + render: (record) => {record.osName || "—"}, + }, + isAdvanced && { + accessor: "cpuModel", + width: 220, + ellipsis: true, + title: t("column.cpuModel"), + sortable: true, + render: (record) => {record.cpuModel || "—"}, + }, + isAdvanced && { + accessor: "cores", + width: 80, + title: t("column.cores"), + sortable: true, + render: (record) => {record.cores}, + }, + isAdvanced && { + accessor: "memoryTotal", + width: 120, + title: t("column.memoryTotal"), + sortable: true, + render: (record) => ( + {record.memoryTotal > 0 ? formatBytes(record.memoryTotal) : "—"} + ), + }, visibleMetricKeys.has("showCpu") && { accessor: "cpu", width: 140, @@ -359,7 +418,7 @@ export default function BeszelSystemTableWidget({ ]; return cols.filter(Boolean) as DataTableColumn[]; - }, [t, size, visibleMetricKeys]); + }, [t, size, visibleMetricKeys, isAdvanced]); const { effectiveColumns, storeKey } = usePersistedTableLayout({ columns, @@ -373,7 +432,7 @@ export default function BeszelSystemTableWidget({ const handleRowClick = useCallback( ({ record }: { record: SystemRowWithKey }) => { - const integrationId = record._key.split(":")[0] ?? ""; + const integrationId = record.rowKey.split(":")[0] ?? ""; openModal({ integrationId, systemId: record.id }, { title: record.name }); }, [openModal], @@ -390,7 +449,10 @@ export default function BeszelSystemTableWidget({ const table = (
    - + + + +
    diff --git a/packages/widgets/src/beszel-system-table/index.ts b/packages/widgets/src/beszel-system-table/index.ts index 4007bebc0..76fb0264f 100644 --- a/packages/widgets/src/beszel-system-table/index.ts +++ b/packages/widgets/src/beszel-system-table/index.ts @@ -25,7 +25,6 @@ const sortDirectionOptions = [ export const { definition, componentLoader } = createWidgetDefinition("beszelSystemTable", { icon: IconTable, - supportsAdvancedFocus: false, queryKeys: [[["widget", "beszel", "getSystems"]], [["widget", "beszel", "getSystemStats"]]], queryMatcher: (query, scope) => query.path.at(-1) === "getSystems" diff --git a/packages/widgets/src/beszel/_shared/system-stats-modal.tsx b/packages/widgets/src/beszel/_shared/system-stats-modal.tsx index bc13d498b..fda3146d2 100644 --- a/packages/widgets/src/beszel/_shared/system-stats-modal.tsx +++ b/packages/widgets/src/beszel/_shared/system-stats-modal.tsx @@ -50,7 +50,6 @@ export const BeszelSystemStatsModal = createModal(( timePeriod={timePeriod} visibility={allCharts} columns={2} - tooltipLayer="modal" onSwitchToHistorical={() => setTimePeriod("1h")} /> diff --git a/packages/widgets/src/bookmarks/component.tsx b/packages/widgets/src/bookmarks/component.tsx index 13e211f53..d16e08ee4 100644 --- a/packages/widgets/src/bookmarks/component.tsx +++ b/packages/widgets/src/bookmarks/component.tsx @@ -111,7 +111,7 @@ export default function BookmarksWidget({ return ( {options.title.length > 0 && ( - + <Title order={4} px="0.25rem" lineClamp={displayMode === "advanced" ? undefined : 1}> {options.title} )} @@ -283,14 +283,14 @@ const AdvancedBookmarksLayout = ({ style={{ width: 40, height: 40, flex: "0 0 auto" }} /> - + {app.name} {getBookmarkHostname(app.href)} {app.description && ( - + {app.description} )} diff --git a/packages/widgets/src/calendar/component.tsx b/packages/widgets/src/calendar/component.tsx index f2b18fed6..8d2e01da6 100644 --- a/packages/widgets/src/calendar/component.tsx +++ b/packages/widgets/src/calendar/component.tsx @@ -10,13 +10,13 @@ import dayjs from "dayjs"; import { clientApi } from "@homarr/api/client"; import { useRequiredBoard } from "@homarr/boards/context"; -import type { CalendarEvent } from "@homarr/integrations/types"; import { useSettings } from "@homarr/settings"; -import { useCurrentIntlLocale, useScopedI18n } from "@homarr/translation/client"; +import { useCurrentIntlLocale, useI18n, useScopedI18n } from "@homarr/translation/client"; import actionTargetClasses from "../common/action-target.module.css"; import type { WidgetComponentProps } from "../definition"; import { getUsableWidgetQueryData } from "../common/query-state"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; import { useWidgetRuntimeQueries } from "../runtime-hooks"; import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; import { CalendarDay } from "./calender-day"; @@ -27,6 +27,7 @@ import { splitEvents, toCalendarDateKey, } from "./calendar-events"; +import type { CalendarEventWithSource } from "./calendar-event-list"; import { CalendarEventList } from "./calendar-event-list"; import classes from "./component.module.css"; @@ -53,6 +54,7 @@ export default function CalendarWidget(props: WidgetComponentProps<"calendar">) events={[]} failedIntegrations={[]} isPending={false} + queryError={undefined} month={month} setMonth={setMonth} /> @@ -79,7 +81,20 @@ const FetchCalendar = ({ month, setMonth, isEditMode, integrationIds, options, d const data = getUsableWidgetQueryData(calendarQuery); const { isPending } = calendarQuery; - const events = useMemo(() => data?.flatMap((item) => item.events) ?? [], [data]); + const events = useMemo( + () => + data?.flatMap(({ events: integrationEvents, integration, error }) => + error + ? [] + : integrationEvents.map( + (event): CalendarEventWithSource => ({ + ...event, + source: { integrationId: integration.id, integrationName: integration.name }, + }), + ), + ) ?? [], + [data], + ); const failedIntegrations = data?.flatMap(({ integration, error }) => error ? [{ integrationId: integration.id, integrationName: integration.name, error }] : [], @@ -91,6 +106,7 @@ const FetchCalendar = ({ month, setMonth, isEditMode, integrationIds, options, d events={events} failedIntegrations={failedIntegrations} isPending={isPending} + queryError={calendarQuery.error} month={month} setMonth={setMonth} options={options} @@ -101,9 +117,10 @@ const FetchCalendar = ({ month, setMonth, isEditMode, integrationIds, options, d interface CalendarBaseProps { isEditMode: boolean; - events: CalendarEvent[]; + events: CalendarEventWithSource[]; failedIntegrations: { integrationId: string; integrationName: string; error: string }[]; isPending: boolean; + queryError: unknown; month: Date; setMonth: (date: Date) => void; options: WidgetComponentProps<"calendar">["options"]; @@ -115,11 +132,13 @@ const CalendarBase = ({ events, failedIntegrations, isPending, + queryError, month, setMonth, options, displayMode, }: CalendarBaseProps) => { + const t = useI18n(); const locale = useCurrentIntlLocale(); const { firstDayOfWeek } = useSettings(); const board = useRequiredBoard(); @@ -151,6 +170,8 @@ const CalendarBase = ({ events={agendaEvents} failedIntegrations={failedIntegrations} isPending={isPending} + queryError={queryError} + queryErrorLabel={t("widget.calendar.name")} isEditMode={isEditMode} locale={locale} month={month} @@ -161,9 +182,10 @@ const CalendarBase = ({ return ( - {failedIntegrations.length > 0 && ( + {(failedIntegrations.length > 0 || Boolean(queryError)) && ( + )} - {failedIntegrations.length > 0 && } + + + + @@ -310,7 +339,7 @@ const CalendarAgenda = ({
    ) : events.length > 0 ? ( - + ) : ( diff --git a/packages/widgets/src/catalog.ts b/packages/widgets/src/catalog.ts index a8a185310..b40a3117c 100644 --- a/packages/widgets/src/catalog.ts +++ b/packages/widgets/src/catalog.ts @@ -34,6 +34,7 @@ import { IconPhoto, IconReportSearch, IconRocket, + IconRobot, IconRoute, IconRss, IconServer2, @@ -56,6 +57,7 @@ export const widgetCatalogIcons: Record = { clock: IconClock, weather: IconCloud, app: IconApps, + assistant: IconRobot, iframe: IconBrowser, video: IconDeviceCctv, notebook: IconNotes, diff --git a/packages/widgets/src/clock/index.ts b/packages/widgets/src/clock/index.ts index 45b040009..e7657b918 100644 --- a/packages/widgets/src/clock/index.ts +++ b/packages/widgets/src/clock/index.ts @@ -6,7 +6,6 @@ import { optionsBuilder } from "../options"; export const { definition, componentLoader } = createWidgetDefinition("clock", { icon: IconClock, - supportsAdvancedFocus: true, queryKey: [["widget", "weather", "atLocation"]], queryMatcher: ({ input }, scope) => { const location = scope.options.weatherLocation; diff --git a/packages/widgets/src/coolify/component.tsx b/packages/widgets/src/coolify/component.tsx index 83449f190..d9c688555 100644 --- a/packages/widgets/src/coolify/component.tsx +++ b/packages/widgets/src/coolify/component.tsx @@ -1,17 +1,26 @@ "use client"; -import { ScrollArea, SimpleGrid, Stack, Text } from "@mantine/core"; +import { Badge, Box, Group, ScrollArea, SimpleGrid, Stack, Text } from "@mantine/core"; import { clientApi } from "@homarr/api/client"; import { useScopedI18n } from "@homarr/translation/client"; -import type { WidgetComponentProps } from "../definition"; import { getUsableWidgetQueryData } from "../common/query-state"; -import { createWidgetKey } from "./coolify-utils"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; +import { WidgetEmptyState } from "../common/empty-state"; +import type { WidgetComponentProps } from "../definition"; +import { createWidgetKey, getCoolifySectionVisibility } from "./coolify-utils"; import { InstanceCard } from "./instance-card"; import { SingleInstanceLayout } from "./single-instance-layout"; +import type { InstanceData } from "./types"; -export default function CoolifyWidget({ options, integrationIds, width, height }: WidgetComponentProps<"coolify">) { +export default function CoolifyWidget({ + options, + integrationIds, + width, + height, + displayMode, +}: WidgetComponentProps<"coolify">) { const t = useScopedI18n("widget.coolify"); if (integrationIds.length === 0) { @@ -22,7 +31,18 @@ export default function CoolifyWidget({ options, integrationIds, width, height } ); } - return ; + const isAdvanced = displayMode === "advanced"; + const sectionVisibility = getCoolifySectionVisibility(options, displayMode); + + return ( + + ); } interface CoolifyContentProps { @@ -30,19 +50,24 @@ interface CoolifyContentProps { options: WidgetComponentProps<"coolify">["options"]; width: number; height: number; + isAdvanced: boolean; } -function CoolifyContent({ integrationIds, options, width, height }: CoolifyContentProps) { +function CoolifyContent({ integrationIds, options, width, height, isAdvanced }: CoolifyContentProps) { const t = useScopedI18n("common"); const instancesQuery = clientApi.widget.coolify.getInstancesInfo.useQuery({ integrationIds, }); const instancesData = getUsableWidgetQueryData(instancesQuery) ?? []; const { isPending } = instancesQuery; + const successfulInstances = instancesData.filter( + (instance): instance is InstanceData => instance.instanceInfo !== null, + ); + const failedInstances = instancesData.filter((instance) => instance.instanceInfo === null); const isTiny = width < 256 || height < 144; const hideFooter = height < 112; - const [firstInstance] = instancesData; + const [firstInstance] = successfulInstances; const widgetKey = createWidgetKey(integrationIds); if (isPending) { @@ -54,33 +79,77 @@ function CoolifyContent({ integrationIds, options, width, height }: CoolifyConte ); } - - if (instancesData.length === 1 && firstInstance) { + if (successfulInstances.length === 0) { return ( - + + + + + + + ); + } + + if (successfulInstances.length === 1 && firstInstance) { + return ( + + +
    + +
    +
    ); } return ( - - = 760 ? 2 : 1} spacing="sm" p="xs"> - {instancesData.map((instance) => ( - - ))} - - + + + + = 760 ? 2 : 1} spacing="sm" p="xs"> + {successfulInstances.map((instance) => ( + + ))} + + + ); } + +const FailedSourceBadges = ({ + sources, + queryError, +}: { + sources: { integrationId: string; integrationName: string }[]; + queryError: unknown; +}) => { + const t = useScopedI18n("widget.coolify"); + if (sources.length === 0 && !queryError) return null; + + return ( + + {sources.map((source) => ( + + {t("source.unavailable", { source: source.integrationName })} + + ))} + + + + + ); +}; diff --git a/packages/widgets/src/coolify/instance-card.tsx b/packages/widgets/src/coolify/instance-card.tsx index 968243fe9..53cb5c4b4 100644 --- a/packages/widgets/src/coolify/instance-card.tsx +++ b/packages/widgets/src/coolify/instance-card.tsx @@ -1,6 +1,7 @@ "use client"; -import { Accordion, Anchor, Badge, Card, Group, Image, Text, Tooltip } from "@mantine/core"; +import { useState } from "react"; +import { Accordion, Anchor, Badge, Card, Group, Image, Stack, Text, Tooltip } from "@mantine/core"; import { useLocalStorage } from "@mantine/hooks"; import { useTimeAgo } from "@homarr/common"; @@ -8,7 +9,7 @@ import { useScopedI18n } from "@homarr/translation/client"; import { ApplicationsSection } from "./applications-section"; import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url"; -import { buildServerResourceCounts, getBadgeColor, parseStatus } from "./coolify-utils"; +import { buildServerResourceCounts, getBadgeColor, isCoolifyServerOnline, parseStatus } from "./coolify-utils"; import { ServersSection } from "./servers-section"; import { ServicesSection } from "./services-section"; import type { CoolifyOptions, InstanceData } from "./types"; @@ -18,11 +19,13 @@ interface InstanceCardProps { instance: InstanceData; options: CoolifyOptions; isTiny: boolean; + isAdvanced: boolean; widgetKey: string; hideFooter: boolean; } -export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter }: InstanceCardProps) { +export function InstanceCard({ instance, options, isTiny, isAdvanced, widgetKey, hideFooter }: InstanceCardProps) { + const t = useScopedI18n("widget.coolify"); const tCommon = useScopedI18n("common"); const cardKey = `${widgetKey}-${instance.integrationId}`; const [showIp, setShowIp] = useLocalStorage({ @@ -33,6 +36,7 @@ export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter key: `coolify-sections-${cardKey}`, defaultValue: ["applications"], }); + const [advancedOpenSections, setAdvancedOpenSections] = useState(["servers", "applications", "services"]); const serverResourceCounts = buildServerResourceCounts( instance.instanceInfo.servers, instance.instanceInfo.applications, @@ -40,7 +44,8 @@ export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter ); const baseUrl = getSafeApplicationUrl(instance.integrationUrl)?.replace(/\/+$/, "") ?? ""; - const onlineServers = instance.instanceInfo.servers.filter((s) => s.is_reachable !== false).length; + const displayUrl = baseUrl ? baseUrl.replace(/^https?:\/\//, "") : "—"; + const onlineServers = instance.instanceInfo.servers.filter(isCoolifyServerOnline).length; const runningApps = instance.instanceInfo.applications.filter( (a) => parseStatus(a.status ?? "") === "running", ).length; @@ -73,20 +78,27 @@ export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter wrap="nowrap" style={{ borderBottom: "1px solid var(--mantine-color-dark-4)" }} > - + Coolify - - {instance.integrationName} - + + + {instance.integrationName} + + {isAdvanced && ( + + {t("source.url", { url: displayUrl })} + + )} + {isTiny && totalResources > 0 ? ( @@ -127,8 +139,8 @@ export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter chevronPosition="right" multiple keepMounted={false} - value={openSections} - onChange={setOpenSections} + value={isAdvanced ? advancedOpenSections : openSections} + onChange={isAdvanced ? setAdvancedOpenSections : setOpenSections} > {options.showServers && ( setShowIp((prev) => !prev)} /> @@ -144,7 +157,12 @@ export function InstanceCard({ instance, options, isTiny, widgetKey, hideFooter )} {options.showServices && ( - + )} diff --git a/packages/widgets/src/coolify/servers-section.tsx b/packages/widgets/src/coolify/servers-section.tsx index 2e79bfdf0..ebd1a2b58 100644 --- a/packages/widgets/src/coolify/servers-section.tsx +++ b/packages/widgets/src/coolify/servers-section.tsx @@ -1,20 +1,28 @@ "use client"; import { Accordion, ActionIcon, Anchor, Badge, Group, Stack, Text } from "@mantine/core"; -import { IconCircleCheckFilled, IconCircleXFilled, IconEye, IconEyeOff, IconServer } from "@tabler/icons-react"; +import { + IconCircleCheckFilled, + IconCircleFilled, + IconCircleXFilled, + IconEye, + IconEyeOff, + IconServer, +} from "@tabler/icons-react"; import type { CoolifyServer } from "@homarr/integrations/types"; import { useScopedI18n } from "@homarr/translation/client"; import actionTargetClasses from "../common/action-target.module.css"; import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url"; -import { getBadgeColor } from "./coolify-utils"; +import { getBadgeColor, getCoolifyServerState, isCoolifyServerOnline } from "./coolify-utils"; interface ServersSectionProps { servers: CoolifyServer[]; serverResourceCounts: Map; baseUrl: string; isTiny: boolean; + isAdvanced: boolean; showIp: boolean; onToggleIp: () => void; } @@ -24,12 +32,13 @@ export function ServersSection({ serverResourceCounts, baseUrl, isTiny, + isAdvanced, showIp, onToggleIp, }: ServersSectionProps) { const t = useScopedI18n("widget.coolify"); const tCommon = useScopedI18n("common"); - const onlineServers = servers.filter((server) => server.is_reachable !== false).length; + const onlineServers = servers.filter(isCoolifyServerOnline).length; return ( @@ -67,6 +76,7 @@ export function ServersSection({ } baseUrl={baseUrl} isTiny={isTiny} + isAdvanced={isAdvanced} showIp={showIp} /> ))} @@ -86,23 +96,28 @@ interface ServerRowProps { counts: { apps: number; services: number }; baseUrl: string; isTiny: boolean; + isAdvanced: boolean; showIp: boolean; } -function ServerRow({ server, counts, baseUrl, isTiny, showIp }: ServerRowProps) { +function ServerRow({ server, counts, baseUrl, isTiny, isAdvanced, showIp }: ServerRowProps) { const t = useScopedI18n("widget.coolify"); const isBuildServer = server.settings?.is_build_server === true; - const isOnline = server.is_reachable !== false; + const reachability = getCoolifyServerState(server, "is_reachable"); + const usability = getCoolifyServerState(server, "is_usable"); const serverUrl = getSafeApplicationUrl(`${baseUrl}/server/${server.uuid}`); - const StatusIcon = isOnline ? IconCircleCheckFilled : IconCircleXFilled; + const status = reachability === true ? "online" : reachability === false ? "offline" : "unknown"; + const StatusIcon = + reachability === true ? IconCircleCheckFilled : reachability === false ? IconCircleXFilled : IconCircleFilled; + const statusColor = reachability === true ? "green" : reachability === false ? "red" : "gray"; return ( - {showIp ? server.ip : "***.***.***.***"} + {showIp ? (server.ip ?? "—") : "***.***.***.***"} + {isAdvanced && ( + + + + + )} ); } + +const ServerStateBadge = ({ field, value }: { field: "reachability" | "usability"; value: boolean | undefined }) => { + const t = useScopedI18n("widget.coolify"); + const status = + value === undefined + ? t("status.unknown") + : field === "reachability" + ? t(value ? "status.reachable" : "status.unreachable") + : t(value ? "status.usable" : "status.unusable"); + return ( + + {t(`server.${field}`)}: {status} + + ); +}; diff --git a/packages/widgets/src/coolify/services-section.tsx b/packages/widgets/src/coolify/services-section.tsx index c225db27d..1961077cc 100644 --- a/packages/widgets/src/coolify/services-section.tsx +++ b/packages/widgets/src/coolify/services-section.tsx @@ -1,21 +1,24 @@ "use client"; -import { Accordion, Badge, Group, Stack, Text } from "@mantine/core"; +import { Accordion, Anchor, Badge, Group, Stack, Text } from "@mantine/core"; import { IconStack2 } from "@tabler/icons-react"; import type { CoolifyServiceWithContext } from "@homarr/integrations/types"; import { useScopedI18n } from "@homarr/translation/client"; -import { getBadgeColor, parseStatus } from "./coolify-utils"; +import actionTargetClasses from "../common/action-target.module.css"; +import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url"; +import { cleanFqdn, getBadgeColor, getStatusColor, parseStatus } from "./coolify-utils"; import { ResourceRow } from "./resource-row"; interface ServicesSectionProps { services: CoolifyServiceWithContext[]; baseUrl: string; isTiny: boolean; + isAdvanced: boolean; } -export function ServicesSection({ services, baseUrl, isTiny }: ServicesSectionProps) { +export function ServicesSection({ services, baseUrl, isTiny, isAdvanced }: ServicesSectionProps) { const t = useScopedI18n("widget.coolify"); const tCommon = useScopedI18n("common"); const runningServices = services.filter((svc) => parseStatus(svc.status ?? "") === "running").length; @@ -34,7 +37,19 @@ export function ServicesSection({ services, baseUrl, isTiny }: ServicesSectionPr {services.length > 0 ? ( {services.map((service) => ( - + + + {isAdvanced && service.applications && service.applications.length > 0 && ( + + + {tCommon("applications")} + + {service.applications.map((application) => ( + + ))} + + )} + ))} ) : ( @@ -46,3 +61,45 @@ export function ServicesSection({ services, baseUrl, isTiny }: ServicesSectionPr ); } + +type ServiceApplication = NonNullable[number]; + +const ServiceApplicationRow = ({ application }: { application: ServiceApplication }) => { + const t = useScopedI18n("widget.coolify"); + const status = parseStatus(application.status ?? ""); + const publicUrl = getSafeApplicationUrl(cleanFqdn(application.fqdn)); + const statusLabel = + status === "running" || + status === "stopped" || + status === "exited" || + status === "starting" || + status === "restarting" + ? t(`status.${status}`) + : t("status.unknown"); + + return ( + + + {statusLabel} + + {publicUrl ? ( + + {application.name} + + ) : ( + + {application.name} + + )} + + ); +}; diff --git a/packages/widgets/src/coolify/single-instance-layout.tsx b/packages/widgets/src/coolify/single-instance-layout.tsx index 342dde60e..4b9252eb5 100644 --- a/packages/widgets/src/coolify/single-instance-layout.tsx +++ b/packages/widgets/src/coolify/single-instance-layout.tsx @@ -1,5 +1,6 @@ "use client"; +import { useState } from "react"; import { Accordion, Anchor, Group, Image, ScrollArea, Stack, Text } from "@mantine/core"; import { useLocalStorage } from "@mantine/hooks"; @@ -18,11 +19,20 @@ interface SingleInstanceLayoutProps { instance: InstanceData; options: CoolifyOptions; isTiny: boolean; + isAdvanced: boolean; widgetKey: string; hideFooter: boolean; } -export function SingleInstanceLayout({ instance, options, isTiny, widgetKey, hideFooter }: SingleInstanceLayoutProps) { +export function SingleInstanceLayout({ + instance, + options, + isTiny, + isAdvanced, + widgetKey, + hideFooter, +}: SingleInstanceLayoutProps) { + const t = useScopedI18n("widget.coolify"); const [showIp, setShowIp] = useLocalStorage({ key: `coolify-show-ip-${widgetKey}`, defaultValue: false, @@ -31,6 +41,7 @@ export function SingleInstanceLayout({ instance, options, isTiny, widgetKey, hid key: `coolify-sections-${widgetKey}`, defaultValue: ["applications"], }); + const [advancedOpenSections, setAdvancedOpenSections] = useState(["servers", "applications", "services"]); const serverResourceCounts = buildServerResourceCounts( instance.instanceInfo.servers, instance.instanceInfo.applications, @@ -49,18 +60,25 @@ export function SingleInstanceLayout({ instance, options, isTiny, widgetKey, hid oolify - - {displayUrl} - + + {isAdvanced && ( + + {instance.integrationName} + + )} + + {isAdvanced ? t("source.url", { url: displayUrl }) : displayUrl} + + {options.showServers && ( setShowIp((prev) => !prev)} /> @@ -85,7 +104,12 @@ export function SingleInstanceLayout({ instance, options, isTiny, widgetKey, hid )} {options.showServices && ( - + )} diff --git a/packages/widgets/src/dns-hole/controls/component.tsx b/packages/widgets/src/dns-hole/controls/component.tsx index 13977a5a0..d9e4b578e 100644 --- a/packages/widgets/src/dns-hole/controls/component.tsx +++ b/packages/widgets/src/dns-hole/controls/component.tsx @@ -6,6 +6,7 @@ import { useState } from "react"; import { ActionIcon, Badge, + Box, Button, Card, Flex, @@ -33,7 +34,9 @@ import { MaskedOrNormalImage } from "@homarr/ui"; import type { widgetKind } from "."; import type { WidgetComponentProps } from "../../definition"; +import { IntegrationErrorIndicator } from "../../common/integration-error-indicator"; import { getUsableWidgetQueryData } from "../../common/query-state"; +import { WidgetQueryErrorIndicator } from "../../common/query-state-indicator"; import actionTargetClasses from "../../common/action-target.module.css"; import classes from "./component.module.css"; import TimerModal from "./TimerModal"; @@ -41,6 +44,15 @@ import TimerModal from "./TimerModal"; const dnsLightStatus = (enabled: boolean | undefined) => `var(--mantine-color-${typeof enabled === "undefined" ? "blue" : enabled ? "green" : "red"}-6`; +type DnsSummaryResult = RouterOutputs["widget"]["dnsHole"]["summary"][number]; +type AvailableDnsSummaryResult = DnsSummaryResult & { + summary: NonNullable; + integration: DnsSummaryResult["integration"] & { updatedAt: Date }; +}; + +const isAvailableDnsSummaryResult = (result: DnsSummaryResult): result is AvailableDnsSummaryResult => + result.summary !== null && result.integration.updatedAt !== undefined; + export default function DnsHoleControlsWidget({ options, integrationIds, @@ -55,7 +67,8 @@ export default function DnsHoleControlsWidget({ .filter((id) => integrationIds.includes(id)); const summaryQuery = clientApi.widget.dnsHole.summary.useQuery({ integrationIds }); - const summaries = getUsableWidgetQueryData(summaryQuery) ?? []; + const summaryResults = getUsableWidgetQueryData(summaryQuery) ?? []; + const summaries = summaryResults.filter(isAvailableDnsSummaryResult); const { isPending: isSummaryPending } = summaryQuery; const utils = clientApi.useUtils(); @@ -84,7 +97,7 @@ export default function DnsHoleControlsWidget({ if (!prevData) return []; return prevData.map((item) => - item.integration.id === integrationId + item.integration.id === integrationId && item.summary ? { ...item, summary: { @@ -147,7 +160,14 @@ export default function DnsHoleControlsWidget({ p="sm" gap="sm" style={{ pointerEvents: isEditMode ? "none" : undefined }} + pos="relative" > + + + + + + {controlAllButtonsVisible && ( @@ -260,7 +280,7 @@ export default function DnsHoleControlsWidget({ interface ControlsCardProps { integrationsWithInteractions: string[]; toggleDns: (integrationId: string) => Promise; - data: RouterOutputs["widget"]["dnsHole"]["summary"][number]; + data: AvailableDnsSummaryResult; setSelectedIntegrationIds: (integrationId: string[]) => void; open: () => void; t: TranslationFunction; diff --git a/packages/widgets/src/downloads/component.tsx b/packages/widgets/src/downloads/component.tsx index 32ab31afa..dcfe40d29 100644 --- a/packages/widgets/src/downloads/component.tsx +++ b/packages/widgets/src/downloads/component.tsx @@ -53,11 +53,18 @@ import { showErrorNotification } from "@homarr/notifications"; import { useCurrentIntlLocale, useScopedI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; +import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; import { getUsableWidgetQueryData } from "../common/query-state"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; import { HomarrDataTable } from "../common/homarr-data-table"; import { formatLocalizedDateTime } from "../common/locale"; import { usePersistedTableLayout, useTableLayoutPersistence } from "../common/use-persisted-table-layout"; -import { filterDownloadItemsByStatus, getAvailableDownloadStates } from "./helpers"; +import { + DOWNLOAD_COLUMN_ACCESSORS, + filterDownloadItemsByStatus, + getAvailableDownloadStates, + getDownloadColumnAccessors, +} from "./helpers"; dayjs.extend(relativeTime); @@ -84,6 +91,7 @@ interface ColumnContext { hasTorrents: boolean; hasMultipleClients: boolean; hasMultipleTypes: boolean; + isAdvanced: boolean; size: SizeConfig; } @@ -143,8 +151,8 @@ const columnVisibilityChecks: Partial boo upSpeed: (ctx) => ctx.hasTorrents && ctx.size.showSpeedColumns, ratio: (ctx) => ctx.hasTorrents, sent: (ctx) => ctx.hasTorrents, - integration: (ctx) => ctx.hasMultipleClients, - type: (ctx) => ctx.hasMultipleTypes, + integration: (ctx) => ctx.isAdvanced || ctx.hasMultipleClients, + type: (ctx) => ctx.isAdvanced || ctx.hasMultipleTypes, downSpeed: (ctx) => ctx.size.showSpeedColumns, time: (ctx) => ctx.size.showTimeColumn, state: (ctx) => ctx.size.showStateColumn, @@ -171,24 +179,6 @@ function progressColor(state: DownloadState, progress: number): string { return "blue"; } -const columnAccessors = [ - "name", - "progress", - "size", - "downSpeed", - "upSpeed", - "time", - "state", - "added", - "ratio", - "received", - "sent", - "category", - "integration", - "index", - "type", -] as const; - function toCategoryArray(category: string | string[]): string[] { if (Array.isArray(category)) return category; return [category]; @@ -320,10 +310,17 @@ export default function DownloadClientsWidget({ integrationIds, limitPerIntegration: options.limitPerIntegration, }); - const currentItems = getUsableWidgetQueryData(downloadsQuery) ?? []; + const currentItems = getUsableWidgetQueryData(downloadsQuery); + const availableItems = useMemo(() => currentItems?.filter((item) => item.data !== null) ?? [], [currentItems]); const { isFetching } = downloadsQuery; const t = useScopedI18n("widget.downloads"); + const queryIndicators = ( + + + + + ); const [clientFilter, setClientFilter] = useState([]); const [statusFilter, setStatusFilter] = useState([]); @@ -370,7 +367,7 @@ export default function DownloadClientsWidget({ }, [options.defaultSort, defaultSortDirection]); const eligibleData = useMemo(() => { - return currentItems + return availableItems .filter(({ integration }) => integrationIds.includes(integration.id)) .flatMap((pair) => pair.data.items @@ -399,7 +396,7 @@ export default function DownloadClientsWidget({ }), ); }, [ - currentItems, + availableItems, integrationIds, integrationInteractSet, mutateDeleteItem, @@ -422,7 +419,7 @@ export default function DownloadClientsWidget({ }, [data, sortStatus]); const clients = useMemo(() => { - return currentItems + return availableItems .filter(({ integration }) => integrationIds.includes(integration.id)) .map(({ integration, data: clientData }): ExtendedClientStatus => { const interact = integrationInteractSet.has(integration.id); @@ -459,7 +456,7 @@ export default function DownloadClientsWidget({ }; }); }, [ - currentItems, + availableItems, integrationIds, integrationInteractSet, options.applyFilterToRatio, @@ -472,10 +469,13 @@ export default function DownloadClientsWidget({ const hasMultipleTypes = new Set(data.map(({ type }) => type)).size > 1; const size = useMemo(() => getSizeConfig(width, height, isAdvanced), [height, isAdvanced, width]); - const optionsColumnSet = useMemo(() => new Set(options.columns), [options.columns]); + const optionsColumnSet = useMemo( + () => new Set(getDownloadColumnAccessors(options.columns, isAdvanced)), + [isAdvanced, options.columns], + ); const columnContext = useMemo( - () => ({ optionsColumnSet, hasTorrents, hasMultipleClients, hasMultipleTypes, size }), - [optionsColumnSet, hasTorrents, hasMultipleClients, hasMultipleTypes, size], + () => ({ optionsColumnSet, hasTorrents, hasMultipleClients, hasMultipleTypes, isAdvanced, size }), + [optionsColumnSet, hasTorrents, hasMultipleClients, hasMultipleTypes, isAdvanced, size], ); let progressColumnWidth = 120; @@ -688,7 +688,7 @@ export default function DownloadClientsWidget({ const { effectiveColumns, storeKey } = usePersistedTableLayout({ columns, - columnAccessors, + columnAccessors: DOWNLOAD_COLUMN_ACCESSORS, columnOrder: options.columnOrder, columnWidths: options.columnWidths, itemId, @@ -733,11 +733,16 @@ export default function DownloadClientsWidget({ return { stateCounts, totalSize, completedSize, totalItems: data.length }; }, [data]); - if (options.columns.length === 0) { + if (!isAdvanced && options.columns.length === 0) { return ( -
    - {t("errors.noColumns")} -
    + + + {queryIndicators} + +
    + {t("errors.noColumns")} +
    +
    ); } @@ -759,10 +764,13 @@ export default function DownloadClientsWidget({ )} + + {queryIndicators} + ( export function getAvailableDownloadStates(items: readonly { state: DownloadState }[]): DownloadState[] { return [...new Set(items.map(({ state }) => state))]; } - -export function columnWidthsToRecord(columnsWidth: readonly Record[]): Record { - const result: Record = {}; - for (const entry of columnsWidth) { - const key = Object.keys(entry)[0]; - if (!key) continue; - const width = entry[key]; - if (typeof width === "number") result[key] = width; - else if (typeof width === "string" && width.endsWith("px")) result[key] = parseInt(width, 10); - } - return result; -} diff --git a/packages/widgets/src/downloads/index.ts b/packages/widgets/src/downloads/index.ts index f2cc93be3..cad34eac4 100644 --- a/packages/widgets/src/downloads/index.ts +++ b/packages/widgets/src/downloads/index.ts @@ -2,28 +2,10 @@ import { IconDownload } from "@tabler/icons-react"; import { z } from "zod/v4"; import { getIntegrationKindsByCategory } from "@homarr/definitions"; -import type { ExtendedDownloadClientItem } from "@homarr/integrations"; import { createWidgetDefinition, widgetQueryInputMatches } from "../definition"; import { optionsBuilder } from "../options"; - -const columnsList = [ - "name", - "progress", - "size", - "downSpeed", - "upSpeed", - "time", - "state", - "added", - "ratio", - "received", - "sent", - "category", - "integration", - "index", - "type", -] as const satisfies (keyof ExtendedDownloadClientItem)[]; +import { DOWNLOAD_COLUMN_ACCESSORS } from "./helpers"; const sortColumns = [ "name", @@ -38,7 +20,7 @@ const sortColumns = [ "sent", "index", "type", -] as const satisfies readonly (typeof columnsList)[number][]; +] as const satisfies readonly (typeof DOWNLOAD_COLUMN_ACCESSORS)[number][]; export const { definition, componentLoader } = createWidgetDefinition("downloads", { icon: IconDownload, @@ -55,7 +37,7 @@ export const { definition, componentLoader } = createWidgetDefinition("downloads (factory) => ({ columns: factory.multiSelect({ defaultValue: ["name", "progress", "downSpeed", "time", "state"], - options: columnsList.map((value) => ({ + options: DOWNLOAD_COLUMN_ACCESSORS.map((value) => ({ value, label: (t) => t(`widget.downloads.items.${value}.columnTitle`), })), diff --git a/packages/widgets/src/errors/component.spec.ts b/packages/widgets/src/errors/component.spec.ts index abe6ca0db..c1bc146c4 100644 --- a/packages/widgets/src/errors/component.spec.ts +++ b/packages/widgets/src/errors/component.spec.ts @@ -46,7 +46,6 @@ describe("WidgetError", () => { MantineProvider, null, createElement(WidgetError, { - kind: "app", error: new Error(secret), resetErrorBoundary: vi.fn(), }), diff --git a/packages/widgets/src/filter-storage-volumes.ts b/packages/widgets/src/filter-storage-volumes.ts index 5e88584be..9c406c65e 100644 --- a/packages/widgets/src/filter-storage-volumes.ts +++ b/packages/widgets/src/filter-storage-volumes.ts @@ -35,11 +35,7 @@ const storageDeviceNamesMatch = (leftDeviceName: string, rightDeviceName: string ); }; -const matchesVisibleStorageVolume = ( - visibleVolume: string, - integrationId: string, - deviceName: string, -): boolean => { +const matchesVisibleStorageVolume = (visibleVolume: string, integrationId: string, deviceName: string): boolean => { const separatorIndex = visibleVolume.indexOf(":"); if (separatorIndex === -1) { return storageDeviceNamesMatch(visibleVolume, deviceName); diff --git a/packages/widgets/src/firewall/component.tsx b/packages/widgets/src/firewall/component.tsx index 905135942..62a553c4f 100644 --- a/packages/widgets/src/firewall/component.tsx +++ b/packages/widgets/src/firewall/component.tsx @@ -37,7 +37,7 @@ interface FirewallQueryState { isPending: boolean; isFetching: boolean; isError: boolean; - data?: readonly { error?: string }[]; + data?: readonly { error?: string; integration?: { id: string } }[]; } export const hasTotalFirewallFailure = (queries: readonly FirewallQueryState[]) => @@ -48,6 +48,13 @@ export const hasTotalFirewallFailure = (queries: readonly FirewallQueryState[]) (query.data !== undefined && query.data.length > 0 && query.data.every(({ error }) => error)), ); +export const hasFirewallPartialFailure = (firewallId: string, queries: readonly FirewallQueryState[]) => + queries.some( + (query) => + query.isError || + query.data?.some(({ error, integration }) => integration?.id === firewallId && Boolean(error)) === true, + ); + export default function FirewallWidget({ integrationIds, width, @@ -101,6 +108,7 @@ export default function FirewallWidget({ const initialSelectedFirewall = firewallIds[0] ?? ""; const activeFirewall = firewallMetadata.has(selectedFirewall) ? selectedFirewall : initialSelectedFirewall; const displayedFirewallIds = isAdvanced ? firewallIds : activeFirewall ? [activeFirewall] : []; + const firewallHasError = (firewallId: string) => hasFirewallPartialFailure(firewallId, queries); const dropdownItems = firewallIds.map((firewallId) => ({ label: firewallMetadata.get(firewallId)?.name ?? firewallId, value: firewallId, @@ -128,11 +136,20 @@ export default function FirewallWidget({ dropdownItems={dropdownItems} isTiny={isTiny} /> - !error)} - selectedFirewall={activeFirewall} - isTiny={isTiny} - /> + + {activeFirewall && firewallHasError(activeFirewall) && ( + + + {t("common.error")} + + + )} + !error)} + selectedFirewall={activeFirewall} + isTiny={isTiny} + /> + )} @@ -142,9 +159,7 @@ export default function FirewallWidget({ const memory = firewallsMemoryData.find(({ integration }) => integration.id === firewallId); const version = firewallsVersionData.find(({ integration }) => integration.id === firewallId); const interfaces = firewallsInterfacesData.find(({ integration }) => integration.id === firewallId); - const hasError = Boolean( - cpu?.error || memory?.error || version?.error || interfacesQuery.isError || interfaces?.error, - ); + const hasError = firewallHasError(firewallId); const metadata = firewallMetadata.get(firewallId); return ( diff --git a/packages/widgets/src/health-monitoring/system-health.tsx b/packages/widgets/src/health-monitoring/system-health.tsx index f8cfafda0..79886384e 100644 --- a/packages/widgets/src/health-monitoring/system-health.tsx +++ b/packages/widgets/src/health-monitoring/system-health.tsx @@ -24,6 +24,8 @@ import { IconCpu2, IconFileReport, IconInfoCircle, + IconPackages, + IconRefreshAlert, IconServer, IconTemperature, IconVersions, @@ -41,7 +43,9 @@ import { useI18n } from "@homarr/translation/client"; import { filterStorageVolumes, normalizeStorageDeviceName } from "../filter-storage-volumes"; import { WidgetEmptyState } from "../common/empty-state"; -import { getUsableWidgetQueryData } from "../common/query-state"; +import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; +import { getUsableWidgetQueryData, isInitialWidgetQueryPending } from "../common/query-state"; +import { WidgetQueryErrorIndicator, WidgetQueryLoadingState } from "../common/query-state-indicator"; import type { WidgetComponentProps } from "../definition"; import actionTargetClasses from "../common/action-target.module.css"; import { CpuRing } from "./rings/cpu-ring"; @@ -60,21 +64,46 @@ export const SystemHealthMonitoring = ({ withScrollArea = true, }: WidgetComponentProps<"healthMonitoring"> & { withScrollArea?: boolean }) => { const t = useI18n(); - const healthData = - getUsableWidgetQueryData(clientApi.widget.healthMonitoring.getSystemHealthStatus.useQuery({ integrationIds })) ?? - []; + const healthQuery = clientApi.widget.healthMonitoring.getSystemHealthStatus.useQuery({ integrationIds }); + const healthResults = getUsableWidgetQueryData(healthQuery) ?? []; + const healthData = healthResults.filter( + (entry): entry is typeof entry & { healthInfo: NonNullable } => entry.healthInfo !== null, + ); const [openedIntegrationId, setOpenedIntegrationId] = useState(null); const board = useRequiredBoard(); const isAdvanced = displayMode === "advanced"; const isTiny = !isAdvanced && width < 256; + const showCpu = isAdvanced || options.cpu; + const showMemory = isAdvanced || options.memory; + const showGpu = isAdvanced || options.gpu; + const showFileSystem = isAdvanced || options.fileSystem; + const queryIndicators = ( + + + + + ); - if (healthData.length === 0) return ; + if (isInitialWidgetQueryPending(healthQuery)) return ; + if (healthData.length === 0) { + return ( + + + {queryIndicators} + + + + ); + } const Container = withScrollArea ? ScrollArea : Box; return ( - + + + {queryIndicators} + {healthData.map(({ integrationId, integrationName, healthInfo }) => { const filteredFileSystem = filterStorageVolumes( @@ -145,18 +174,18 @@ export const SystemHealthMonitoring = ({ - {options.cpu && } - {options.cpu && ( + {showCpu && } + {showCpu && ( )} - {options.memory && ( + {showMemory && ( )} - {options.gpu && + {showGpu && healthInfo.gpu.map((gpu) => ( ))} @@ -166,7 +195,7 @@ export const SystemHealthMonitoring = ({ )} - {options.fileSystem && + {showFileSystem && disksData.map((disk) => { return ( ; const SystemInformationList = ({ healthInfo, @@ -285,6 +316,14 @@ const SystemInformationList = ({ {healthInfo.loadAverage["5min"]}% / {healthInfo.loadAverage["15min"]}% )} + }> + {t("widget.healthMonitoring.popover.updatesAvailable", { count: healthInfo.availablePkgUpdates })} + + }> + {healthInfo.rebootRequired + ? t("widget.healthMonitoring.popover.rebootRequired") + : t("widget.healthMonitoring.popover.rebootNotRequired")} + ); diff --git a/packages/widgets/src/immich/albums-query.spec.ts b/packages/widgets/src/immich/albums-query.spec.ts index 377a22c1c..85faa58bc 100644 --- a/packages/widgets/src/immich/albums-query.spec.ts +++ b/packages/widgets/src/immich/albums-query.spec.ts @@ -13,12 +13,19 @@ const mocks = vi.hoisted(() => ({ getAlbums: vi.fn(() => ({ data: [], isPending: false, isError: false })), })); +vi.mock("@trpc/react-query", () => ({ + getQueryKey: (procedure: { path: string[] }, input: unknown) => [procedure.path, { input, type: "query" }], +})); + vi.mock("@homarr/api/client", () => ({ clientApi: { widget: { immich: { - getAlbums: { useQuery: mocks.getAlbums }, - getServerStats: { useQuery: () => ({ data: undefined }) }, + getAlbums: { path: ["widget", "immich", "getAlbums"], useQuery: mocks.getAlbums }, + getServerStats: { + path: ["widget", "immich", "getServerStats"], + useQuery: () => ({ data: undefined }), + }, }, }, }, diff --git a/packages/widgets/src/indexer-manager/index.ts b/packages/widgets/src/indexer-manager/index.ts index c61bd84c1..8cc1e0eed 100644 --- a/packages/widgets/src/indexer-manager/index.ts +++ b/packages/widgets/src/indexer-manager/index.ts @@ -13,7 +13,6 @@ const createOptions = () => })); export const { definition, componentLoader } = createWidgetDefinition("indexerManager", { - supportsAdvancedFocus: false, icon: IconReportSearch, contextActions: ({ widgetRuntimeRef, context }) => [ { diff --git a/packages/widgets/src/manifest.spec.ts b/packages/widgets/src/manifest.spec.ts index a7c0b77f3..2cb9a373c 100644 --- a/packages/widgets/src/manifest.spec.ts +++ b/packages/widgets/src/manifest.spec.ts @@ -15,6 +15,7 @@ import { } from "./manifest"; import { widgetQueryRefetchIntervals } from "./refetch-intervals"; import { widgetCatalogIcons } from "./catalog"; +import { getWidgetQueryKeys } from "./definition"; describe("widget manifest promise stability", () => { it("returns the same module promise for every render", () => { @@ -111,11 +112,11 @@ describe("widget manifest promise stability", () => { const definitions = await loadAllWidgetDefinitions(); const expectedQueryKeys = new Map([ ["anchorNote", [["widget", "anchorNotes"]]], - ["beszelAlerts", [["widget", "beszel"]]], - ["clock", [["widget", "weather"]]], - ["mediaMissing", [["widget", "mediaOrganizer"]]], - ["mediaRequests-requestList", [["widget", "mediaRequests"]]], - ["mediaRequests-requestStats", [["widget", "mediaRequests"]]], + ["beszelAlerts", [["widget", "beszel", "getAlerts"]]], + ["clock", [["widget", "weather", "atLocation"]]], + ["mediaMissing", [["widget", "mediaOrganizer", "getData"]]], + ["mediaRequests-requestList", [["widget", "mediaRequests", "getLatestRequests"]]], + ["mediaRequests-requestStats", [["widget", "mediaRequests", "getStats"]]], ["smartHome-entityState", [["widget", "smartHome"]]], ] as const); @@ -133,14 +134,15 @@ describe("widget manifest promise stability", () => { const definition = definitions.get(kind); if (definition?.refetchInterval === undefined) continue; - const entry = { - queryKey: definition.queryKey ?? [["widget", kind]], - intervalSeconds: definition.refetchInterval, - } as const; - const serializedQueryKey = JSON.stringify(entry.queryKey); - const existing = expectedByQueryKey.get(serializedQueryKey); - expect(existing?.intervalSeconds ?? entry.intervalSeconds).toBe(entry.intervalSeconds); - expectedByQueryKey.set(serializedQueryKey, entry); + for (const queryKey of getWidgetQueryKeys(definition, kind)) { + const path = queryKey[0]; + if (!Array.isArray(path) || (path[0] !== "widget" && path[0] !== "docker")) continue; + const entry = { queryKey, intervalSeconds: definition.refetchInterval } as const; + const serializedQueryKey = JSON.stringify(entry.queryKey); + const existing = expectedByQueryKey.get(serializedQueryKey); + expect(existing?.intervalSeconds ?? entry.intervalSeconds).toBe(entry.intervalSeconds); + expectedByQueryKey.set(serializedQueryKey, entry); + } } const serializePolicy = (entry: PollingPolicy) => JSON.stringify(entry); diff --git a/packages/widgets/src/manifest.ts b/packages/widgets/src/manifest.ts index 3fd61a0df..3e12ea75b 100644 --- a/packages/widgets/src/manifest.ts +++ b/packages/widgets/src/manifest.ts @@ -25,6 +25,7 @@ const moduleLoaders: Record Promise> = { clock: () => import("./clock") as Promise, weather: () => import("./weather") as Promise, app: () => import("./app") as Promise, + assistant: () => import("./assistant") as Promise, archiveTeamWarrior: () => import("./archive-team-warrior") as Promise, anchorNote: () => import("./anchor-note") as Promise, notebook: () => import("./notebook") as Promise, @@ -85,6 +86,7 @@ const componentLoaders: Record Promise> clock: () => import("./clock/component") as Promise, weather: () => import("./weather/component") as Promise, app: () => import("./app/component") as Promise, + assistant: () => import("./assistant/component") as Promise, archiveTeamWarrior: () => import("./archive-team-warrior/component") as Promise, anchorNote: () => import("./anchor-note/component") as Promise, notebook: () => import("./notebook/component") as Promise, diff --git a/packages/widgets/src/media-missing/component.tsx b/packages/widgets/src/media-missing/component.tsx index acc9f765e..3d4ec2503 100644 --- a/packages/widgets/src/media-missing/component.tsx +++ b/packages/widgets/src/media-missing/component.tsx @@ -28,6 +28,7 @@ import { useScopedI18n } from "@homarr/translation/client"; import { WidgetEmptyState } from "../common/empty-state"; import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url"; import { getUsableWidgetQueryData } from "../common/query-state"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; import type { WidgetComponentProps } from "../definition"; import { useWidgetRuntimeQueries } from "../runtime-hooks"; import { NoIntegrationDataError } from "../errors/no-data-integration"; @@ -45,18 +46,19 @@ export default function MediaMissingWidget({ }: WidgetComponentProps<"mediaMissing">) { const t = useScopedI18n("widget.mediaMissing"); const isAdvanced = displayMode === "advanced"; + const showMissing = isAdvanced || options.showMissing; + const showQueued = isAdvanced || options.showQueued; const pageSize = isAdvanced ? Math.max(Number(options.pageSize), 50) : Number(options.pageSize); const input = { integrationIds, pageSize }; useWidgetRuntimeQueries(widgetRuntimeRef, [getQueryKey(clientApi.widget.mediaOrganizer.getData, input, "query")]); - const data = getUsableWidgetQueryData( - clientApi.widget.mediaOrganizer.getData.useQuery(input, { - staleTime: 60 * 1000, - refetchOnWindowFocus: false, - refetchOnReconnect: false, - }), - ); - const [selectedTab, setSelectedTab] = useState(options.showMissing ? "missing" : "queued"); - const activeTab = resolveMediaMissingTab(selectedTab, options.showMissing, options.showQueued); + const mediaQuery = clientApi.widget.mediaOrganizer.getData.useQuery(input, { + staleTime: 60 * 1000, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + }); + const data = getUsableWidgetQueryData(mediaQuery); + const [selectedTab, setSelectedTab] = useState(showMissing ? "missing" : "queued"); + const activeTab = resolveMediaMissingTab(selectedTab, showMissing, showQueued); useEffect(() => { if (activeTab !== null && activeTab !== selectedTab) setSelectedTab(activeTab); @@ -64,7 +66,7 @@ export default function MediaMissingWidget({ if (!data) return ; if (data.length === 0) throw new NoIntegrationDataError(); - if (!options.showMissing && !options.showQueued) + if (!showMissing && !showQueued) return (
    @@ -79,7 +81,7 @@ export default function MediaMissingWidget({ const queuedCount = data.reduce((sum, entry) => sum + entry.queuedCount, 0); const failedIntegrations = data.filter((entry): entry is typeof entry & { error: string } => Boolean(entry.error)); - const enabledPanelCount = Number(options.showMissing) + Number(options.showQueued); + const enabledPanelCount = Number(showMissing) + Number(showQueued); const panelWidth = isAdvanced && enabledPanelCount > 1 ? width / enabledPanelCount : width; const isThin = !isAdvanced && panelWidth > 0 && panelWidth < 160; const isShort = !isAdvanced && height > 0 && height < 180; @@ -102,7 +104,12 @@ export default function MediaMissingWidget({ ) : ( {entries.map(({ item, integrationId }) => ( - + ))} )} @@ -121,13 +128,17 @@ export default function MediaMissingWidget({ ))} ); + const queryFailure = ; if (isAdvanced) { return ( - {partialFailures} + + {queryFailure} + {partialFailures} + - {options.showMissing && ( + {showMissing && ( @@ -138,7 +149,7 @@ export default function MediaMissingWidget({ {renderPanel(missing, t("empty.missing"))} )} - {options.showQueued && ( + {showQueued && ( @@ -164,26 +175,29 @@ export default function MediaMissingWidget({ h="100%" style={{ display: "flex", flexDirection: "column" }} > - {partialFailures} + + {queryFailure} + {partialFailures} + - {options.showMissing && ( + {showMissing && ( }> {tabLabel(t("tab.missing"), missing.length, missingCount)} )} - {options.showQueued && ( + {showQueued && ( }> {tabLabel(t("tab.queued"), queued.length, queuedCount)} )} - {options.showMissing && ( + {showMissing && ( {activeTab === "missing" && renderPanel(missing, t("empty.missing"))} )} - {options.showQueued && ( + {showQueued && ( {activeTab === "queued" && renderPanel(queued, t("empty.queued"))} @@ -307,7 +321,15 @@ const CardShell = ({ ); }; -const MediaCard = ({ item, density }: { item: MissingMediaItem | QueuedMediaItem; density: Density }) => { +const MediaCard = ({ + item, + density, + showQueueDetails, +}: { + item: MissingMediaItem | QueuedMediaItem; + density: Density; + showQueueDetails: boolean; +}) => { const isQueued = "percentComplete" in item; return ( @@ -324,6 +346,11 @@ const MediaCard = ({ item, density }: { item: MissingMediaItem | QueuedMediaItem {item.type === "episode" ? item.title : item.year} )} + {isQueued && showQueueDetails && ( + + {[item.status, item.timeLeft].filter(Boolean).join(" · ")} + + )} {isQueued && } diff --git a/packages/widgets/src/media-releases/component.tsx b/packages/widgets/src/media-releases/component.tsx index df9d0f409..f574a48bb 100644 --- a/packages/widgets/src/media-releases/component.tsx +++ b/packages/widgets/src/media-releases/component.tsx @@ -31,6 +31,7 @@ import { OverflowBadge } from "@homarr/ui"; import { WidgetEmptyState } from "../common/empty-state"; import type { WidgetComponentProps } from "../definition"; import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url"; +import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; import { getUsableWidgetQueryData, isInitialWidgetQueryPending } from "../common/query-state"; import { WidgetQueryErrorIndicator, WidgetQueryLoadingState } from "../common/query-state-indicator"; import classes from "./component.module.css"; @@ -44,36 +45,43 @@ export default function MediaReleasesWidget({ }: WidgetComponentProps<"mediaReleases">) { const t = useI18n(); const releasesQuery = clientApi.widget.mediaRelease.getMediaReleases.useQuery({ integrationIds }); - const releases = getUsableWidgetQueryData(releasesQuery); + const response = getUsableWidgetQueryData(releasesQuery); if (isInitialWidgetQueryPending(releasesQuery)) return ; - if (!releases || releases.length === 0) return ; + if (!response) return ; + + const { releases, failedIntegrations } = response; const isAdvanced = displayMode === "advanced"; return ( - - - {releases.map((item, index) => ( - - {!isAdvanced && index !== 0 && options.layout === "poster" && } - - - ))} - - - {releasesQuery.error && ( - + {releases.length === 0 ? ( + + ) : ( + + + {releases.map((item, index) => ( + + {!isAdvanced && index !== 0 && options.layout === "poster" && } + + + ))} + + + )} + {(failedIntegrations.length > 0 || releasesQuery.error) && ( + + - + )} ); } interface ItemProps { - item: RouterOutputs["widget"]["mediaRelease"]["getMediaReleases"][number]; + item: RouterOutputs["widget"]["mediaRelease"]["getMediaReleases"]["releases"][number]; options: WidgetComponentProps<"mediaReleases">["options"]; isAdvanced: boolean; width: number; @@ -213,7 +221,7 @@ const Item = ({ item, options, isAdvanced, width, height }: ItemProps) => { /> )} {isAdvanced && item.description && ( - + {item.description} )} @@ -232,9 +240,17 @@ const Item = ({ item, options, isAdvanced, width, height }: ItemProps) => { )} - {(isAdvanced || options.showSource) && ( - - )} + {(isAdvanced || options.showSource) && + (isAdvanced ? ( + + + + {item.integration.name} + + + ) : ( + + ))} )} diff --git a/packages/widgets/src/media-server/component.tsx b/packages/widgets/src/media-server/component.tsx index f8406ef13..ea0043b53 100644 --- a/packages/widgets/src/media-server/component.tsx +++ b/packages/widgets/src/media-server/component.tsx @@ -37,6 +37,7 @@ import { useTranslatedMantineReactTable } from "@homarr/ui/hooks"; import type { WidgetComponentProps } from "../definition"; import { getUsableWidgetQueryData } from "../common/query-state"; import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; import classes from "./component.module.css"; type TranscodingDecision = NonNullable["metadata"]>["transcoding"]; @@ -74,16 +75,17 @@ export default function MediaServerWidget({ isEditMode, displayMode, }: WidgetComponentProps<"mediaServer">) { - const currentStreams = - getUsableWidgetQueryData( - clientApi.widget.mediaServer.getCurrentStreams.useQuery({ - integrationIds, - showOnlyPlaying: options.showOnlyPlaying, - }), - ) ?? []; + const currentStreamsQuery = clientApi.widget.mediaServer.getCurrentStreams.useQuery({ + integrationIds, + showOnlyPlaying: options.showOnlyPlaying, + }); + const currentStreamsData = getUsableWidgetQueryData(currentStreamsQuery); + const currentStreams = useMemo(() => currentStreamsData ?? [], [currentStreamsData]); const t = useScopedI18n("widget.mediaServer"); const isAdvanced = displayMode === "advanced"; + const showLocation = isAdvanced || options.showLocation; + const showBitrate = isAdvanced || options.showBitrate; const [selectedRowId, setSelectedRowId] = useState(null); const columns = useMemo[]>(() => { const result: MRT_ColumnDef[] = [ @@ -142,8 +144,8 @@ export default function MediaServerWidget({ if (!currentlyPlaying) return null; const status = getPlaybackStatus(currentlyPlaying.metadata?.transcoding); - const location = options.showLocation ? currentlyPlaying.location : null; - const bitrateLabel = options.showBitrate ? formatBitrate(currentlyPlaying.metadata?.bitrateKbps) : null; + const location = showLocation ? currentlyPlaying.location : null; + const bitrateLabel = showBitrate ? formatBitrate(currentlyPlaying.metadata?.bitrateKbps) : null; return ( @@ -175,7 +177,7 @@ export default function MediaServerWidget({ : []), ]; return result; - }, [isAdvanced, options.showBitrate, options.showLocation, selectedRowId, t, width]); + }, [isAdvanced, selectedRowId, showBitrate, showLocation, t, width]); // 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 @@ -285,7 +287,7 @@ export default function MediaServerWidget({ (sum, session) => sum + (session.currentlyPlaying?.metadata?.bitrateKbps ?? 0), 0, ); - const totalBitrateLabel = options.showBitrate ? formatBitrate(totalBitrateKbps) : null; + const totalBitrateLabel = showBitrate ? formatBitrate(totalBitrateKbps) : null; const hasFailedIntegrations = currentStreams.some(({ error }) => Boolean(error)); return ( @@ -300,12 +302,14 @@ export default function MediaServerWidget({ {t("summary.transcoding", { count: transcodingCount })} + )} - {!isAdvanced && hasFailedIntegrations && ( + {!isAdvanced && (hasFailedIntegrations || currentStreamsQuery.error) && ( + )} diff --git a/packages/widgets/src/media-transcoding/component.tsx b/packages/widgets/src/media-transcoding/component.tsx index eddf8adea..a651bbf73 100644 --- a/packages/widgets/src/media-transcoding/component.tsx +++ b/packages/widgets/src/media-transcoding/component.tsx @@ -4,6 +4,7 @@ import { useEffect, useState } from "react"; import type { ReactNode } from "react"; import { getQueryKey } from "@trpc/react-query"; import { + Box, Center, Divider, Group, @@ -26,6 +27,7 @@ import { views } from "."; import { WidgetEmptyState } from "../common/empty-state"; import type { WidgetComponentProps } from "../definition"; import { getUsableWidgetQueryData } from "../common/query-state"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; import { useWidgetRuntimeQueries } from "../runtime-hooks"; import { HealthCheckStatus } from "./health-check-status"; import { QueuePanel } from "./panels/queue.panel"; @@ -66,7 +68,8 @@ export default function MediaTranscodingWidget({ useWidgetRuntimeQueries(widgetRuntimeRef, [ getQueryKey(clientApi.widget.mediaTranscoding.getDataAsync, input, "query"), ]); - const transcodingData = getUsableWidgetQueryData(clientApi.widget.mediaTranscoding.getDataAsync.useQuery(input)); + const transcodingQuery = clientApi.widget.mediaTranscoding.getDataAsync.useQuery(input); + const transcodingData = getUsableWidgetQueryData(transcodingQuery); const [view, setView] = useState(options.defaultView); const t = useI18n("widget.mediaTranscoding"); @@ -94,10 +97,16 @@ export default function MediaTranscodingWidget({ const queuePageCount = totalQueuePages ?? 1; const isTiny = !isAdvanced && (width < 280 || height < 140); const footerLayout = getTranscodingFooterLayout(width, height); + const queryIndicator = ( + + + + ); if (isAdvanced) { return ( - + + {queryIndicator} = 1100 ? 3 : width >= 700 ? 2 : 1} spacing="sm"> @@ -127,7 +136,8 @@ export default function MediaTranscodingWidget({ } return ( - + + {queryIndicator} {view === "workers" ? ( ) : view === "queue" ? ( diff --git a/packages/widgets/src/notebook/notebook.tsx b/packages/widgets/src/notebook/notebook.tsx index db6850baf..25ea9586d 100644 --- a/packages/widgets/src/notebook/notebook.tsx +++ b/packages/widgets/src/notebook/notebook.tsx @@ -70,6 +70,7 @@ import type { TablerIcon } from "@homarr/ui"; import type { WidgetComponentProps } from "../definition"; import actionTargetClasses from "../common/action-target.module.css"; import { createReadOnlyTaskItemTransaction, ReadOnlyTaskItem } from "./read-only-task-item"; +import { getNotebookDisplay } from "./display"; import { NotebookTextDirection, setTextDirection } from "./text-direction"; import "@mantine/tiptap/styles.css"; @@ -98,6 +99,7 @@ export function Notebook({ boardId, itemId, height, + displayMode = "compact", }: WidgetComponentProps<"notebook">) { const [content, setContent] = useState(options.content); const previousContentRef = useRef(options.content); @@ -339,6 +341,13 @@ export function Notebook({ characters: documentText.length, words: documentText.length === 0 ? 0 : documentText.split(/\s+/).length, }; + const display = getNotebookDisplay({ + height, + isAdvanced: displayMode === "advanced", + isEditing, + isSaving, + showToolbar: options.showToolbar, + }); return ( @@ -375,9 +384,9 @@ export function Notebook({ > @@ -505,7 +514,7 @@ export function Notebook({ - {(saveError || height >= 180) && ( + {(saveError || display.showDocumentStats) && ( {saveError && ( @@ -521,7 +530,7 @@ export function Notebook({ )} - {height >= 180 && ( + {display.showDocumentStats && ( {t("widget.notebook.documentStats", documentStats)} diff --git a/packages/widgets/src/notifications/component.tsx b/packages/widgets/src/notifications/component.tsx index 59f42bd96..a003ae6e8 100644 --- a/packages/widgets/src/notifications/component.tsx +++ b/packages/widgets/src/notifications/component.tsx @@ -9,21 +9,25 @@ import { useRequiredBoard } from "@homarr/boards/context"; import { useTimeAgo } from "@homarr/common"; import { useI18n } from "@homarr/translation/client"; -import type { WidgetComponentProps } from "../definition"; import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url"; import { getUsableWidgetQueryData } from "../common/query-state"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; +import type { WidgetComponentProps } from "../definition"; +import { getNotificationDisplay } from "./display"; export default function NotificationsWidget({ options, integrationIds, width, height, + displayMode, }: WidgetComponentProps<"notifications">) { const notificationsQuery = clientApi.widget.notifications.getNotifications.useQuery({ ...options, integrationIds, }); - const notificationIntegrations = getUsableWidgetQueryData(notificationsQuery) ?? []; + const notificationData = getUsableWidgetQueryData(notificationsQuery); + const notificationIntegrations = useMemo(() => notificationData ?? [], [notificationData]); const { isPending } = notificationsQuery; const t = useI18n(); @@ -49,12 +53,23 @@ export default function NotificationsWidget({ const isDense = width < 280 || height < 180; const isRoomy = width >= 360 && height >= 220; const bodyLineClamp = height < 112 ? 1 : isDense ? 2 : height >= 300 ? 8 : 4; + const notificationDisplay = getNotificationDisplay({ + displayMode, + hideLogos: options.hideLogos, + isRoomy, + bodyLineClamp, + }); const columns = width >= 720 ? 2 : 1; const spacing = isRoomy ? "sm" : "xs"; return ( + {notificationsQuery.error && ( + + + + )} {failedIntegrations.length > 0 && ( {failedIntegrations.map((integration) => ( @@ -95,7 +110,7 @@ export default function NotificationsWidget({ }} > - {!options.hideLogos && notification.source?.iconUrl && ( + {notificationDisplay.showLogos && notification.source?.iconUrl && ( {notification.body} @@ -121,7 +136,11 @@ export default function NotificationsWidget({ diff --git a/packages/widgets/src/notifications/index.ts b/packages/widgets/src/notifications/index.ts index 6358d8303..60bdc8758 100644 --- a/packages/widgets/src/notifications/index.ts +++ b/packages/widgets/src/notifications/index.ts @@ -6,7 +6,7 @@ import { createWidgetDefinition, widgetQueryInputMatches } from "../definition"; import { optionsBuilder } from "../options"; export const { componentLoader, definition } = createWidgetDefinition("notifications", { - supportsAdvancedFocus: false, + supportsAdvancedFocus: true, icon: IconMessage, queryKey: [["widget", "notifications", "getNotifications"]], queryMatcher: ({ input }, scope) => diff --git a/packages/widgets/src/patchmon/index.ts b/packages/widgets/src/patchmon/index.ts index 2bd52e383..d715e90ac 100644 --- a/packages/widgets/src/patchmon/index.ts +++ b/packages/widgets/src/patchmon/index.ts @@ -190,18 +190,42 @@ export const { definition, componentLoader } = createWidgetDefinition("patchmon" useCustomThresholds: { shouldHide: (options) => !options.enableThresholdColors, }, - hostsNeedingUpdatesThresholdMode: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, - hostsNeedingUpdatesWarningAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, - hostsNeedingUpdatesCriticalAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, - securityUpdatesThresholdMode: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, - securityUpdatesWarningAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, - securityUpdatesCriticalAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, - hostsWithSecurityUpdatesThresholdMode: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, - hostsWithSecurityUpdatesWarningAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, - hostsWithSecurityUpdatesCriticalAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, - upToDateHostsThresholdMode: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, - upToDateHostsWarningAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, - upToDateHostsCriticalAt: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds }, + hostsNeedingUpdatesThresholdMode: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, + hostsNeedingUpdatesWarningAt: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, + hostsNeedingUpdatesCriticalAt: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, + securityUpdatesThresholdMode: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, + securityUpdatesWarningAt: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, + securityUpdatesCriticalAt: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, + hostsWithSecurityUpdatesThresholdMode: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, + hostsWithSecurityUpdatesWarningAt: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, + hostsWithSecurityUpdatesCriticalAt: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, + upToDateHostsThresholdMode: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, + upToDateHostsWarningAt: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, + upToDateHostsCriticalAt: { + shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds, + }, totalOutdatedPackagesThresholdMode: { shouldHide: (options) => !options.enableThresholdColors || !options.useCustomThresholds || !options.showTotalOutdatedPackages, diff --git a/packages/widgets/src/releases/index.ts b/packages/widgets/src/releases/index.ts index 0507e8f42..75a42f203 100644 --- a/packages/widgets/src/releases/index.ts +++ b/packages/widgets/src/releases/index.ts @@ -13,7 +13,7 @@ const relativeDateSchema = z .or(z.literal("")); export const { definition, componentLoader } = createWidgetDefinition("releases", { - supportsAdvancedFocus: false, + supportsAdvancedFocus: true, icon: IconRocket, queryKey: [["widget", "releases", "getLatest"]], queryMatcher: ({ input }, scope) => widgetQueryInputMatches(input, { itemId: scope.itemId }), diff --git a/packages/widgets/src/rssFeed/component.tsx b/packages/widgets/src/rssFeed/component.tsx index feda0ed07..0da60d804 100644 --- a/packages/widgets/src/rssFeed/component.tsx +++ b/packages/widgets/src/rssFeed/component.tsx @@ -9,8 +9,10 @@ import { clientApi } from "@homarr/api/client"; import { useRequiredBoard } from "@homarr/boards/context"; import { useScopedI18n } from "@homarr/translation/client"; -import type { WidgetComponentProps } from "../definition"; import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url"; +import { WidgetEmptyState } from "../common/empty-state"; +import { WidgetQueryLoadingState } from "../common/query-state-indicator"; +import type { WidgetComponentProps } from "../definition"; import { BaseWidgetError } from "../errors/base-component"; import classes from "./component.module.scss"; @@ -27,6 +29,7 @@ const useLiveFeed = (input: RouterInputs["widget"]["rssFeed"]["getFeeds"]) => { hasError: false as const, entries: normalizedData, failedFeedCount: 0, + isPending: query.isPending, isStale: Boolean(query.error), }; } @@ -35,11 +38,12 @@ const useLiveFeed = (input: RouterInputs["widget"]["rssFeed"]["getFeeds"]) => { hasError: false as const, entries: normalizedData?.entries ?? [], failedFeedCount: normalizedData?.failedFeedCount ?? 0, + isPending: query.isPending, isStale: Boolean(query.error), }; }; -export default function RssFeed({ options, width, height }: WidgetComponentProps<"rssFeed">) { +export default function RssFeed({ options, width, height, displayMode }: WidgetComponentProps<"rssFeed">) { const feed = useLiveFeed({ urls: options.feedUrls, maximumAmountPosts: typeof options.maximumAmountPosts === "number" ? options.maximumAmountPosts : 100, @@ -57,6 +61,7 @@ export default function RssFeed({ options, width, height }: WidgetComponentProps /> ); } + if (feed.isPending) return ; const warning = feed.isStale ? t("warning.stale") @@ -64,13 +69,35 @@ export default function RssFeed({ options, width, height }: WidgetComponentProps ? t("warning.partial", { count: feed.failedFeedCount }) : undefined; + if (feed.entries.length === 0) { + return ( + + {warning && ( + } p="xs"> + {warning} + + )} + + + ); + } + const languageDir = options.enableRtl ? "RTL" : "LTR"; const isDense = width < 420 || height < 180; const isTiny = width < 260 || height < 110; const isRoomy = width >= 420 && height >= 240; + const isAdvanced = displayMode === "advanced"; const columns = width >= 720 && height >= 260 ? 2 : 1; const descriptionLines = isRoomy ? Math.max(options.textLinesClamp, 6) : isDense ? 1 : options.textLinesClamp; + const entryDisplay = getRssEntryDisplay({ + isAdvanced, + isDense, + isTiny, + hideDescription: options.hideDescription, + showPosterImage: options.showPosterImage, + descriptionLines, + }); const spacing = isRoomy ? "sm" : "xs"; return ( @@ -97,7 +124,7 @@ export default function RssFeed({ options, width, height }: WidgetComponentProps title={feedEntry.title} > - {feedEntry.enclosure !== undefined && options.showPosterImage && !isTiny && ( + {feedEntry.enclosure !== undefined && entryDisplay.showImage && ( - + {feedEntry.title} - {!options.hideDescription && feedEntry.description && !isTiny && ( - + {entryDisplay.showDescription && feedEntry.description && ( + {feedDescriptionToText(feedEntry.description)} )} @@ -152,15 +190,44 @@ export const getHostname = (url: string): string => { } }; -const InfoDisplay = ({ date, source }: { date?: string; source?: string }) => ( - +interface RssEntryDisplayInput { + isAdvanced: boolean; + isDense: boolean; + isTiny: boolean; + hideDescription: boolean; + showPosterImage: boolean; + descriptionLines: number; +} + +export const getRssEntryDisplay = ({ + isAdvanced, + isDense, + isTiny, + hideDescription, + showPosterImage, + descriptionLines, +}: RssEntryDisplayInput) => ({ + showDescription: isAdvanced || (!hideDescription && !isTiny), + showImage: isAdvanced || (showPosterImage && !isTiny), + showSource: isAdvanced || !isDense, + descriptionLineClamp: isAdvanced ? undefined : descriptionLines, +}); + +const InfoDisplay = ({ date, timestamp, source }: { date?: string; timestamp?: string; source?: string }) => ( + {date && } {date && ( {date} )} - {date && source && •} + {timestamp && •} + {timestamp && ( + + {timestamp} + + )} + {(date || timestamp) && source && •} {source && ( {source} diff --git a/packages/widgets/src/rssFeed/index.ts b/packages/widgets/src/rssFeed/index.ts index 683dd07ef..abf728aa0 100644 --- a/packages/widgets/src/rssFeed/index.ts +++ b/packages/widgets/src/rssFeed/index.ts @@ -11,7 +11,7 @@ import { optionsBuilder } from "../options"; * - https://www.jsonfeed.org/version/1.1/ */ export const { definition, componentLoader } = createWidgetDefinition("rssFeed", { - supportsAdvancedFocus: false, + supportsAdvancedFocus: true, icon: IconRss, queryKey: [["widget", "rssFeed", "getFeeds"]], queryMatcher: ({ input }, scope) => diff --git a/packages/widgets/src/stocks/index.ts b/packages/widgets/src/stocks/index.ts index 2b6e637e6..ea6398180 100644 --- a/packages/widgets/src/stocks/index.ts +++ b/packages/widgets/src/stocks/index.ts @@ -12,7 +12,7 @@ const timeRangeOptions = stockPriceTimeFrames.range; const timeIntervalOptions = stockPriceTimeFrames.interval; export const { definition, componentLoader } = createWidgetDefinition("stockPrice", { - supportsAdvancedFocus: false, + supportsAdvancedFocus: true, icon: IconBuildingBank, queryKey: [["widget", "stockPrice", "getPriceHistory"]], queryMatcher: ({ input }, scope) => diff --git a/packages/widgets/src/system-disks/component.tsx b/packages/widgets/src/system-disks/component.tsx index 3ca7ae5b8..e320bd2e4 100644 --- a/packages/widgets/src/system-disks/component.tsx +++ b/packages/widgets/src/system-disks/component.tsx @@ -9,16 +9,21 @@ import { formatBytesPair } from "@homarr/common"; import { useI18n } from "@homarr/translation/client"; import { WidgetEmptyState } from "../common/empty-state"; -import { getUsableWidgetQueryData } from "../common/query-state"; +import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; +import { getUsableWidgetQueryData, isInitialWidgetQueryPending } from "../common/query-state"; +import { WidgetQueryErrorIndicator, WidgetQueryLoadingState } from "../common/query-state-indicator"; import type { WidgetComponentProps } from "../definition"; import { filterStorageVolumes, normalizeStorageDeviceName } from "../filter-storage-volumes"; import { NoIntegrationDataError } from "../errors/no-data-integration"; -type DisplayMode = WidgetComponentProps<"systemDisks">["options"]["displayMode"]; +type DiskDisplayMode = WidgetComponentProps<"systemDisks">["options"]["displayMode"]; + +export const clampPercentage = (percentage: number): number => Math.min(100, Math.max(0, percentage)); export const getDisplayText = ( item: { used: string; available: string; percentage: number }, - displayMode: DisplayMode, + displayMode: DiskDisplayMode, + translatedFreeText?: string, ) => { switch (displayMode) { case "percentage": @@ -27,27 +32,26 @@ export const getDisplayText = ( const usedInBytes = Number(item.used); const availableInBytes = Number(item.available); if (Number.isFinite(usedInBytes) && Number.isFinite(availableInBytes)) { - const { used, available } = formatBytesPair(usedInBytes, availableInBytes); - return `${used} / ${available}`; + const { used, available: total } = formatBytesPair(usedInBytes, usedInBytes + availableInBytes); + return `${used} / ${total}`; } return `${item.used} / ${item.available}`; } case "free": - return `${Math.round(100 - item.percentage)}% free`; + return translatedFreeText ?? `${Math.round(100 - clampPercentage(item.percentage))}% free`; default: return `${Math.round(item.percentage)}%`; } }; -export const clampPercentage = (percentage: number): number => Math.min(100, Math.max(0, percentage)); - -const getAbsoluteText = (item: { used: string; available: string }) => { - const usedInBytes = Number(item.used); - const availableInBytes = Number(item.available); - if (!Number.isFinite(usedInBytes) || !Number.isFinite(availableInBytes)) return `${item.used} / ${item.available}`; - const { used, available } = formatBytesPair(usedInBytes, availableInBytes); - return `${used} / ${available}`; -}; +export const getAdvancedDisplayTexts = ( + item: { used: string; available: string; percentage: number }, + translatedFreeText?: string, +) => ({ + percentage: getDisplayText(item, "percentage"), + absolute: getDisplayText(item, "absolute"), + free: getDisplayText(item, "free", translatedFreeText), +}); interface SystemDiskCardProps { deviceName: string; @@ -58,6 +62,9 @@ interface SystemDiskCardProps { showBackgroundBar: boolean; integrationName?: string; secondaryText?: string; + freeText?: string; + smartStatus?: string; + isAdvanced: boolean; showSecondaryText: boolean; showTemperature: boolean; } @@ -71,6 +78,9 @@ const SystemDiskCard = ({ showBackgroundBar, integrationName, secondaryText, + freeText, + smartStatus, + isAdvanced, showSecondaryText, showTemperature, }: SystemDiskCardProps) => { @@ -99,7 +109,9 @@ const SystemDiskCard = ({ }, []); const unhealthyLabel = t("widget.systemDisks.status.unhealthy"); - const hasHiddenTemperature = temperature !== null && temperature !== undefined && !showTemperature; + const hasTemperature = temperature !== null && temperature !== undefined; + const temperatureText = hasTemperature ? `${temperature}°C` : "—°C"; + const hasHiddenTemperature = hasTemperature && !showTemperature; const hasHiddenSecondaryText = Boolean(secondaryText && secondaryText !== displayText && !showSecondaryText); const tooltipLabel = [ healthy ? displayText : `${displayText} (${unhealthyLabel})`, @@ -141,11 +153,19 @@ const SystemDiskCard = ({ {secondaryText} )} + {isAdvanced && freeText && freeText !== displayText && ( + + {freeText} + + )} + {isAdvanced && ( + + {t("widget.systemDisks.status.smart")}: {smartStatus?.trim() || "—"} + + )}
    - {showTemperature && temperature !== null && temperature !== undefined ? ( - {temperature}°C - ) : null} + {showTemperature && (hasTemperature || isAdvanced) ? {temperatureText} : null}
    ) { + const t = useI18n(); const queryInput = { integrationIds }; - const data = - getUsableWidgetQueryData(clientApi.widget.healthMonitoring.getSystemHealthStatus.useQuery(queryInput)) ?? []; + const healthQuery = clientApi.widget.healthMonitoring.getSystemHealthStatus.useQuery(queryInput); + const results = getUsableWidgetQueryData(healthQuery) ?? []; + const data = results.filter( + (entry): entry is typeof entry & { healthInfo: NonNullable } => entry.healthInfo !== null, + ); + const queryIndicators = ( + + + + + ); + const emptyState = ( + + + {queryIndicators} + + + + ); - if (data.length === 0) return ; + if (isInitialWidgetQueryPending(healthQuery)) return ; + if (data.length === 0) return emptyState; const disks = data.flatMap((entry) => { const fileSystem = filterStorageVolumes( @@ -194,32 +234,52 @@ export default function SystemResources({ })); }); - if (data.every((entry) => entry.healthInfo.fileSystem.length === 0)) throw new NoIntegrationDataError(); - if (disks.length === 0) return ; + const hasNoFileSystems = data.every((entry) => entry.healthInfo.fileSystem.length === 0); + const hasFailedSource = results.some((entry) => Boolean(entry.error)); + if (hasNoFileSystems && !hasFailedSource && !healthQuery.error) throw new NoIntegrationDataError(); + if (hasNoFileSystems || disks.length === 0) return emptyState; + const isAdvanced = displayMode === "advanced"; const minimumCardWidth = 260; const columns = Math.max(1, Math.min(disks.length, Math.floor(width / minimumCardWidth))); const cellWidth = width / columns; return ( - - - {disks.map(({ integrationId, integrationName, item, smartItem }) => ( - 1 ? integrationName : undefined} - secondaryText={getAbsoluteText(item)} - showSecondaryText={height >= 160 && cellWidth >= 260} - showTemperature={height >= 100 && cellWidth >= 220} - /> - ))} - - + + + {queryIndicators} + + + + {disks.map(({ integrationId, integrationName, item, smartItem }) => { + const freeText = t("widget.systemDisks.status.free", { + percentage: String(Math.round(100 - clampPercentage(item.percentage))), + }); + const advancedDisplayTexts = getAdvancedDisplayTexts(item, freeText); + + return ( + 1 ? integrationName : undefined} + secondaryText={advancedDisplayTexts.absolute} + freeText={advancedDisplayTexts.free} + smartStatus={smartItem?.overallStatus} + isAdvanced={isAdvanced} + showSecondaryText={isAdvanced || (height >= 160 && cellWidth >= 260)} + showTemperature={isAdvanced || (height >= 100 && cellWidth >= 220)} + /> + ); + })} + + + ); } diff --git a/packages/widgets/src/system-resources/component.tsx b/packages/widgets/src/system-resources/component.tsx index 018a3388f..87f0984dc 100644 --- a/packages/widgets/src/system-resources/component.tsx +++ b/packages/widgets/src/system-resources/component.tsx @@ -4,10 +4,13 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { Box, Center, Group, Loader, ScrollArea, SimpleGrid, Stack, Text } from "@mantine/core"; import { clientApi } from "@homarr/api/client"; +import { useScopedI18n } from "@homarr/translation/client"; import { WidgetEmptyState } from "../common/empty-state"; +import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; import type { WidgetComponentProps } from "../definition"; import { getUsableWidgetQueryData } from "../common/query-state"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; import { CombinedNetworkTrafficChart } from "./chart/combined-network-traffic"; import { SystemResourceCPUChart } from "./chart/cpu-chart"; import { SystemResourceGPUChart } from "./chart/gpu-chart"; @@ -16,6 +19,9 @@ import { NetworkTrafficChart } from "./chart/network-traffic"; const COMPACT_HISTORY_SIZE = 15; const ADVANCED_HISTORY_SIZE = 60; +const ALL_SYSTEM_CHARTS = ["cpu", "memory", "gpu", "network"] as const; + +type SystemChart = WidgetComponentProps<"systemResources">["options"]["visibleCharts"][number]; type ChartItem = { cpu: number; @@ -51,6 +57,26 @@ export const getCompactChartBudget = (height: number): number => { return 4; }; +export const getVisibleSystemCharts = ({ + configuredCharts, + hasGpu, + hasNetwork, + height, + isAdvanced, +}: { + configuredCharts: readonly SystemChart[]; + hasGpu: boolean; + hasNetwork: boolean; + height: number; + isAdvanced: boolean; +}): SystemChart[] => { + const selectedCharts = isAdvanced ? ALL_SYSTEM_CHARTS : configuredCharts; + const availableCharts = selectedCharts.filter( + (chart) => (chart !== "gpu" || !isAdvanced || hasGpu) && (chart !== "network" || hasNetwork), + ); + return isAdvanced ? [...availableCharts] : availableCharts.slice(0, getCompactChartBudget(height)); +}; + export default function SystemResources({ integrationIds, options, @@ -58,13 +84,23 @@ export default function SystemResources({ height, displayMode, }: WidgetComponentProps<"systemResources">) { + const t = useScopedI18n("widget.systemResources"); const healthQuery = clientApi.widget.healthMonitoring.getSystemHealthStatus.useQuery({ integrationIds }); - const data = getUsableWidgetQueryData(healthQuery) ?? []; + const results = getUsableWidgetQueryData(healthQuery) ?? []; + const data = results.filter( + (entry): entry is typeof entry & { healthInfo: NonNullable } => entry.healthInfo !== null, + ); const { dataUpdatedAt, isPending } = healthQuery; const isAdvanced = displayMode === "advanced"; const integrationKey = useMemo(() => integrationIds.join("\u0000"), [integrationIds]); const [historyByIntegration, setHistoryByIntegration] = useState>({}); const previousIntegrationKey = useRef(integrationKey); + const queryIndicators = ( + + + + + ); useEffect(() => { if (previousIntegrationKey.current === integrationKey) return; @@ -102,6 +138,7 @@ export default function SystemResources({ key={entry.integrationId} integrationName={entry.integrationName} items={history} + hasGpu={entry.healthInfo.gpu.length > 0} memoryCapacityInBytes={entry.healthInfo.memAvailableInBytes + entry.healthInfo.memUsedInBytes} options={options} width={availableWidth} @@ -120,11 +157,23 @@ export default function SystemResources({ ); } - if (data.length === 0) return ; + if (data.length === 0) { + return ( + + + {queryIndicators} + + + + ); + } if (!isAdvanced && data.length === 1 && data[0]) { return ( - + + + {queryIndicators} + {renderCharts(data[0], width, Math.max(0, height - 20))} ); @@ -133,17 +182,23 @@ export default function SystemResources({ const compactPanelHeight = Math.max(160, Math.floor(height / Math.min(data.length, 2))); return ( - - - {data.map((entry) => renderCharts(entry, panelWidth, isAdvanced ? height : compactPanelHeight))} - - + + + {queryIndicators} + + + + {data.map((entry) => renderCharts(entry, panelWidth, isAdvanced ? height : compactPanelHeight))} + + + ); } interface SystemChartsProps { integrationName: string; items: ChartItem[]; + hasGpu: boolean; memoryCapacityInBytes: number; options: WidgetComponentProps<"systemResources">["options"]; width: number; @@ -155,6 +210,7 @@ interface SystemChartsProps { const SystemCharts = ({ integrationName, items, + hasGpu, memoryCapacityInBytes, options, width, @@ -163,9 +219,15 @@ const SystemCharts = ({ showTitle, }: SystemChartsProps) => { const networkItems = getNetworkHistory(items); - const availableCharts = options.visibleCharts.filter((chart) => chart !== "network" || networkItems.length > 0); - const visibleCharts = isAdvanced ? availableCharts : availableCharts.slice(0, getCompactChartBudget(height)); + const visibleCharts = getVisibleSystemCharts({ + configuredCharts: options.visibleCharts, + hasGpu, + hasNetwork: networkItems.length > 0, + height, + isAdvanced, + }); const showNetwork = visibleCharts.includes("network"); + const labelDisplayMode = isAdvanced ? "textWithIcon" : options.labelDisplayMode; const chartCount = visibleCharts.length; const chartColumns = isAdvanced && width >= 560 ? 2 : 1; const chartHeight = isAdvanced @@ -192,7 +254,7 @@ const SystemCharts = ({ item.cpu)} hasShadow={options.hasShadow} - labelDisplayMode={options.labelDisplayMode} + labelDisplayMode={labelDisplayMode} /> )} @@ -202,7 +264,7 @@ const SystemCharts = ({ memoryUsageOverTime={items.map((item) => item.memory)} totalCapacityInBytes={memoryCapacityInBytes} hasShadow={options.hasShadow} - labelDisplayMode={options.labelDisplayMode} + labelDisplayMode={labelDisplayMode} /> )} @@ -211,7 +273,7 @@ const SystemCharts = ({ item.gpu)} hasShadow={options.hasShadow} - labelDisplayMode={options.labelDisplayMode} + labelDisplayMode={labelDisplayMode} /> )} @@ -222,13 +284,13 @@ const SystemCharts = ({ usageOverTime={networkItems.map((network) => network.down)} isUp={false} hasShadow={options.hasShadow} - labelDisplayMode={options.labelDisplayMode} + labelDisplayMode={labelDisplayMode} /> network.up)} isUp hasShadow={options.hasShadow} - labelDisplayMode={options.labelDisplayMode} + labelDisplayMode={labelDisplayMode} /> ) : ( @@ -236,7 +298,7 @@ const SystemCharts = ({ ))} diff --git a/packages/widgets/src/test/translation.spec.ts b/packages/widgets/src/test/translation.spec.ts index 7f65261e0..fb8f63843 100644 --- a/packages/widgets/src/test/translation.spec.ts +++ b/packages/widgets/src/test/translation.spec.ts @@ -5,38 +5,47 @@ import { createLanguageMapping } from "@homarr/translation"; import { loadAllWidgetDefinitions } from "../manifest"; +const doesOptionRenderTranslatedCopy = (option: unknown) => { + if (typeof option !== "object" || option === null || !("type" in option)) return false; + return option.type !== "internal" && option.type !== "customWidgetConfiguration"; +}; + const widgetDefinitions = await loadAllWidgetDefinitions(); const enTranslation = await createLanguageMapping().en(); describe("Widget properties with description should have matching translations", () => { for (const [key, definition] of widgetDefinitions) { - Object.entries(definition.createOptions({} as SettingsContextProps)).forEach(([optionKey, optionValue_]) => { - const optionValue = optionValue_ as { withDescription: boolean }; - it(`should have matching translations for ${optionKey} option description of ${key} widget`, () => { - const option = enTranslation.default.widget[key].option; - if (!(optionKey in option)) { - throw new Error(`Option ${optionKey} not found in translation`); - } - const value = option[optionKey as keyof typeof option]; + Object.entries(definition.createOptions({} as SettingsContextProps)) + .filter(([, option]) => doesOptionRenderTranslatedCopy(option)) + .forEach(([optionKey, optionValue_]) => { + const optionValue = optionValue_ as { withDescription: boolean }; + it(`should have matching translations for ${optionKey} option description of ${key} widget`, () => { + const option = enTranslation.default.widget[key].option; + if (!(optionKey in option)) { + throw new Error(`Option ${optionKey} not found in translation`); + } + const value = option[optionKey as keyof typeof option]; - expect("description" in value).toBe(optionValue.withDescription); + expect("description" in value).toBe(optionValue.withDescription); + }); }); - }); } }); describe("Widget properties should have matching name translations", () => { for (const [key, definition] of widgetDefinitions) { - Object.keys(definition.createOptions({} as SettingsContextProps)).forEach((optionKey) => { - it(`should have matching translations for ${optionKey} option name of ${key} widget`, () => { - const option = enTranslation.default.widget[key].option; - if (!(optionKey in option)) { - throw new Error(`Option ${optionKey} not found in translation`); - } - const value = option[optionKey as keyof typeof option]; + Object.entries(definition.createOptions({} as SettingsContextProps)) + .filter(([, option]) => doesOptionRenderTranslatedCopy(option)) + .forEach(([optionKey]) => { + it(`should have matching translations for ${optionKey} option name of ${key} widget`, () => { + const option = enTranslation.default.widget[key].option; + if (!(optionKey in option)) { + throw new Error(`Option ${optionKey} not found in translation`); + } + const value = option[optionKey as keyof typeof option]; - expect("label" in value).toBe(true); + expect("label" in value).toBe(true); + }); }); - }); } }); diff --git a/packages/widgets/src/uptime-kuma/component.tsx b/packages/widgets/src/uptime-kuma/component.tsx index 6dccbbb11..c7c803898 100644 --- a/packages/widgets/src/uptime-kuma/component.tsx +++ b/packages/widgets/src/uptime-kuma/component.tsx @@ -9,8 +9,10 @@ import { formatNumber } from "@homarr/common"; import { useScopedI18n } from "@homarr/translation/client"; import { WidgetEmptyState } from "../common/empty-state"; +import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; import type { WidgetComponentProps } from "../definition"; import { getUsableWidgetQueryData } from "../common/query-state"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; import { NoIntegrationDataError } from "../errors/no-data-integration"; import classes from "./component.module.css"; import { aggregateUptimeKumaDashboards } from "./aggregate"; @@ -128,12 +130,16 @@ interface UptimeKumaContentProps { function UptimeKumaContent({ integrationIds, options, width, height, displayMode }: UptimeKumaContentProps) { const t = useScopedI18n("widget.uptimeKuma"); - const dashboardData = getUsableWidgetQueryData(clientApi.widget.uptimeKuma.getDashboard.useQuery({ integrationIds })); + const dashboardQuery = clientApi.widget.uptimeKuma.getDashboard.useQuery({ integrationIds }); + const dashboardData = getUsableWidgetQueryData(dashboardQuery); if (!dashboardData) return ; + const successfulDashboardData = dashboardData.flatMap((item) => + item.dashboard === null ? [] : [{ ...item, dashboard: item.dashboard }], + ); - const combined = aggregateUptimeKumaDashboards(dashboardData.map((item) => item.dashboard)); - const monitors = dashboardData.flatMap((result) => + const combined = aggregateUptimeKumaDashboards(successfulDashboardData.map((item) => item.dashboard)); + const monitors = successfulDashboardData.flatMap((result) => result.dashboard.monitors.map((monitor) => ({ ...monitor, key: `${result.integrationId}:${monitor.id}`, @@ -145,25 +151,22 @@ function UptimeKumaContent({ integrationIds, options, width, height, displayMode const ringSize = getRingSize(width); const iconSize = getIconSize(width); const gridCols = getGridCols(width); + const isAdvanced = displayMode === "advanced"; const enabledStatKeys = Object.entries(statVisibilityByOption) - .filter(([optionKey]) => options[optionKey as keyof typeof options]) + .filter(([optionKey]) => isAdvanced || options[optionKey as keyof typeof options]) .map(([, statKey]) => statKey); - const showHero = options.showAverageUptime; - const showRing = options.showUptimeRing && (displayMode === "advanced" || (width >= 170 && height >= 110)); - const prioritizedStatKeys = - displayMode === "advanced" - ? enabledStatKeys - : enabledStatKeys.toSorted( - (left, right) => - getCompactStatPriority(left, combined[left]) - getCompactStatPriority(right, combined[right]), - ); + const showHero = isAdvanced || options.showAverageUptime; + const showRing = isAdvanced || (options.showUptimeRing && width >= 170 && height >= 110); + const prioritizedStatKeys = isAdvanced + ? enabledStatKeys + : enabledStatKeys.toSorted( + (left, right) => getCompactStatPriority(left, combined[left]) - getCompactStatPriority(right, combined[right]), + ); const visibleStatKeys = prioritizedStatKeys.slice( 0, - displayMode === "advanced" - ? prioritizedStatKeys.length - : getCompactStatLimit(height, showHero, prioritizedStatKeys.length), + isAdvanced ? prioritizedStatKeys.length : getCompactStatLimit(height, showHero, prioritizedStatKeys.length), ); const hasContent = showHero || visibleStatKeys.length > 0; @@ -245,7 +248,17 @@ function UptimeKumaContent({ integrationIds, options, width, height, displayMode
    ); - if (displayMode === "compact") return summaryContent; + if (displayMode === "compact") { + return ( + + + + + + {summaryContent} + + ); + } const monitorList = ( @@ -257,7 +270,7 @@ function UptimeKumaContent({ integrationIds, options, width, height, displayMode {monitor.name} - {dashboardData.length > 1 && ( + {(isAdvanced || successfulDashboardData.length > 1) && ( {monitor.integrationName} @@ -274,20 +287,32 @@ function UptimeKumaContent({ integrationIds, options, width, height, displayMode if (width < 760) { return ( - - - {summaryContent} - {monitorList} - - + + + + + + + + {summaryContent} + {monitorList} + + + ); } return ( - - {summaryContent} - {monitorList} - + + + + + + + {summaryContent} + {monitorList} + + ); } diff --git a/packages/widgets/src/wud/component.tsx b/packages/widgets/src/wud/component.tsx index 1c744d2cd..0895aeb2b 100644 --- a/packages/widgets/src/wud/component.tsx +++ b/packages/widgets/src/wud/component.tsx @@ -11,36 +11,49 @@ import type { WudContainerUpdate } from "@homarr/integrations"; import { useScopedI18n } from "@homarr/translation/client"; import { WidgetEmptyState } from "../common/empty-state"; +import { getSafeApplicationUrl, SAFE_NEW_TAB_REL } from "../common/application-url"; +import { WidgetQueryErrorIndicator } from "../common/query-state-indicator"; import type { WidgetComponentProps } from "../definition"; import classes from "./component.module.css"; -export default function WudWidget({ integrationIds, options, width }: WidgetComponentProps<"wud">) { +export default function WudWidget({ integrationIds, options, width, displayMode }: WidgetComponentProps<"wud">) { const integrationId = integrationIds[0]; if (!integrationId) return null; - return ; + return ( + + ); } const WudWidgetContent = ({ integrationId, options, width, + isAdvanced, }: { integrationId: string; options: WidgetComponentProps<"wud">["options"]; width: number; + isAdvanced: boolean; }) => { const t = useScopedI18n("widget.wud"); - const [data] = clientApi.widget.wud.getStats.useSuspenseQuery({ integrationId }); + const [data, statsQuery] = clientApi.widget.wud.getStats.useSuspenseQuery({ integrationId }); const board = useRequiredBoard(); - const isTiny = width < 256; + const isTiny = !isAdvanced && width < 256; const stats = data.stats; if (stats.totalContainers === 0) return ; const updatePercentage = Math.round((stats.updatesAvailable / stats.totalContainers) * 100); const badgeColor = stats.updatesAvailable === 0 ? "green" : progressColor(updatePercentage); - const showUpdateList = options.showUpdateList && stats.updates.length > 0; + const showTitle = isAdvanced || options.showTitle; + const showRing = isAdvanced || options.showRing; + const showUpdateList = (isAdvanced || options.showUpdateList) && stats.updates.length > 0; const ring = ( ); - const tinyContent = options.showRing ? ( + const tinyContent = showRing ? ( @@ -102,7 +115,12 @@ const WudWidgetContent = ({ return ( - {options.showTitle && !isTiny && ( + {Boolean(statsQuery.error) && ( + + + + )} + {showTitle && !isTiny && ( @@ -122,12 +140,12 @@ const WudWidgetContent = ({ tinyContent ) : options.layout === "horizontal" ? ( - {options.showRing && ring} + {showRing && ring} {summary} ) : ( - {options.showRing && ring} + {showRing && ring} {summary} )} @@ -181,6 +199,7 @@ const UpdateCard = ({ className: string | undefined; }) => { const t = useScopedI18n("widget.wud"); + const href = getSafeApplicationUrl(update.link); const isDigestUpdate = isDigestVersion(update.newVersion); const fullVersionText = buildVersionText(update.currentVersion, update.newVersion); const versionText = isDigestUpdate @@ -201,12 +220,12 @@ const UpdateCard = ({ {showVersionTooltip ? {versionBadge} : versionBadge} - {update.link && ( + {href && ( /dev/null 2>&1; then - echo "act is required: https://nektosact.com/installation/" >&2 - exit 1 -fi - -socket="${DOCKER_HOST:-}" -if [ -z "$socket" ]; then - socket="$(docker context inspect --format '{{ (index .Endpoints "docker").Host }}' 2>/dev/null || true)" -fi -if [ -z "$socket" ]; then - socket="unix:///var/run/docker.sock" -fi - -exec act workflow_dispatch \ - --workflows .github/workflows/deployment-workshop.yml \ - --job deploy \ - --env ACT=true \ - --container-daemon-socket "$socket" \ - --container-architecture linux/amd64