Compare commits

...
Author SHA1 Message Date
homarr-renovate[bot] dbda477c77 chore(deps): update dependency next-auth to v5.0.0-beta.32 [security] (#6840)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-09-13 14:25:25 +00:00
homarr-renovate[bot] a5c92b114e chore(deps): update dependency hono@<4.6.5 to >=4.13.7 [security] (#6842)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-09-13 03:53:52 +00:00
homarr-renovate[bot] 58ac28d6b5 chore(deps): update dependency @auth/core to v0.41.3 [security] (#6839)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-09-13 00:05:05 +00:00
Kushie 43a57a2dad fix(firewall widget): allow content to shrink and scroll (#6818) 2026-09-12 10:49:01 +02:00
Releases Homarr 7859faaa1d chore(release): 1.77.1 [skip ci] 2026-09-11 19:22:36 +00:00
homarr-releases[bot] bff6ec735e chore(release): automatic release v1.77.1 2026-09-11 19:21:19 +00:00
Thomas 1fbe844598 fix(settings): move board access control out of the nested form (#6662) 2026-09-10 18:13:56 +02:00
Thomas 365ef7f02b Revert "feat: announce Homarr v2 beta" (#6813) 2026-09-10 16:36:54 +02:00
homarr-releases[bot] 2b1a03849d chore: update bug report template (#6798) 2026-09-06 22:31:26 +02:00
Releases Homarr 4c243bc374 chore(release): 1.77.0 [skip ci] 2026-09-06 19:31:37 +00:00
homarr-releases[bot] ecd02f73c0 chore(release): automatic release v1.77.0 2026-09-06 19:30:29 +00:00
Thomas cd23b36f3c fix(ci): use pinned pnpm for releases (#6796) 2026-09-06 21:18:30 +02:00
homarr-releases[bot] f7f29eade9 chore(release): automatic release v1.77.0 2026-09-06 18:47:01 +00:00
Thomas 32a51c1e60 feat: announce Homarr v2 beta (#6793)
* feat: announce Homarr v2 beta

* chore: refine v2 beta announcement

* feat: expand v2 beta guidance

* chore: refine v2 beta resources

* chore: simplify v2 beta modal

* chore: improve v2 beta feedback links

* fix: keep v2 modal above header

* chore: sharpen v2 beta message

* fix: clear header for v2 modal
2026-09-06 20:36:04 +02:00
homarr-crowdin[bot] da32acb4f0 chore(lang): updated translations from crowdin
* chore(lang): update translations from crowdin

* chore(lang): update translations from crowdin

* chore(lang): update translations from crowdin

---------

Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-09-06 01:52:04 +00:00
homarr-update-contributors[bot] 1da13d9bb3 chore: update contributors (#6767)
Co-authored-by: Homarr Update Contributors <210161987+homarr-update-contributors[bot]@users.noreply.github.com>
2026-09-04 15:58:09 +00:00
homarr-crowdin[bot] cb0fec088f chore(lang): updated translations from crowdin
* chore(lang): update translations from crowdin

* chore(lang): update translations from crowdin

---------

Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-09-03 02:05:21 +00:00
homarr-crowdin[bot] a2fe8dd461 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-09-01 02:36:36 +00:00
homarr-update-contributors[bot] b6dfcd69ba chore: update contributors (#6735)
Co-authored-by: Homarr Update Contributors <210161987+homarr-update-contributors[bot]@users.noreply.github.com>
2026-08-28 21:54:00 +00:00
homarr-crowdin[bot]andThomas a38b0ef71d chore(lang): updated translations from crowdin (#6732)
Co-authored-by: Thomas <thomas@ajnart.fr>
2026-08-28 14:07:42 +02:00
Thomas 2cf3027eeb Merge pull request #6720 from homarr-labs/docs/update-helm-docs
docs(helm): update chart installation page
2026-08-28 08:32:40 +02:00
homarr-releases[bot] fa18f6fc71 chore: update bug report template (#6724) 2026-08-28 08:32:03 +02:00
Releases Homarr 331925c197 chore(release): 1.76.2 [skip ci] 2026-08-27 20:09:22 +00:00
Thomas 0e51f745d3 Merge pull request #6723 from homarr-labs/dev
chore(release): automatic release v1.76.2
2026-08-27 22:08:05 +02:00
Thomas d6f720d0e6 Revert "feat(http): set custom User-Agent on outbound integration requests (#6606)" (#6722)
This reverts commit ddbf05524b.
2026-08-27 22:00:23 +02:00
Thomas 5324bf12d4 fix(startup): use stable internal service addresses (#6721) 2026-08-27 21:52:54 +02:00
github-actions[bot] 2922a02ecf docs(helm): update chart installation page 2026-08-27 17:09:27 +00:00
Thomas 87cdcf28e0 fix(mcp): return valid string for void tool results (#6703) 2026-08-27 11:10:37 +02:00
homarr-releases[bot] 441b181e79 chore: update bug report template (#6716)
Co-authored-by: Releases Homarr <175486441+homarr-releases[bot]@users.noreply.github.com>
2026-08-27 11:08:43 +02:00
Releases Homarr eba639b59c chore(release): 1.76.1 [skip ci] 2026-08-26 16:43:52 +00:00
Thomas Camlong da36283ad1 chore(release): retrigger release pipeline 2026-08-26 18:30:12 +02:00
Thomas Camlong c050368782 chore(release): trigger release pipeline 2026-08-26 18:16:26 +02:00
homarr-releases[bot] 82b50f0fd7 chore(release): automatic release v1.76.1 2026-08-26 15:50:55 +00:00
Thomas a0149d5894 Merge pull request #6673 from homarr-labs/investigate-6672-immich-401 2026-08-22 19:44:03 +02:00
ajnart 8579fcbfc2 test(http,immich): address CodeRabbit review
- guarantee server teardown via try/finally in both wire-level tests
- add tuple-array HeadersInit coverage to the helper suite
2026-08-22 17:21:38 +02:00
ajnart b6f3aba23e test(http,immich): prove User-Agent fix at the wire level
Add two regression tests that fail on v1.76.0 and pass with the fix:
- wire-level test: a Headers instance (the shape @immich/sdk hands over)
  must reach the remote server with all headers intact
- real-SDK e2e: getServerStatistics through fetchWithTrustedCertificatesAsync
  against a live local server must deliver x-api-key
2026-08-22 17:16:31 +02:00
ajnart 31e218295d fix(http): preserve SDK headers when injecting User-Agent
The v1.76.0 User-Agent injection object-spread `fetchOptions.headers`, which
silently drops all headers when the value is a Headers instance. The Immich
SDK passes a Headers object with the merged x-api-key header, so requests
lost their API key and returned 401 (issue #6672). Build a real Headers
instance instead, keeping case-insensitive user-agent handling.
2026-08-22 17:12:43 +02:00
Thomas aca3b5d861 fix: correct Unraid CPU, link context menus, and board resizing (#6510)
Fix Unraid logical CPU averaging, preserve native context menus for app and bookmark widgets in view mode, and prevent scrollbar-width GridStack resize oscillation.
2026-08-22 10:53:26 +02:00
homarr-crowdin[bot] a7a2f0223a chore(lang): updated translations from crowdin (#6596)
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-08-22 08:49:51 +02:00
homarr-releases[bot] 7773fdc10b chore: update bug report template (#6655) 2026-08-21 22:14:45 +02:00
Thomas 7019a1d0a4 Merge pull request #6656 from homarr-labs/docs/update-helm-docs 2026-08-21 22:14:26 +02:00
github-actions[bot] 2d535caeac docs(helm): update chart installation page 2026-08-21 17:41:09 +00:00
Releases Homarr 2013fbe80d chore(release): 1.76.0 [skip ci] 2026-08-21 17:20:50 +00:00
homarr-releases[bot] 219ef58926 chore(release): automatic release v1.76.0 2026-08-21 17:19:40 +00:00
homarr-update-contributors[bot] 97195bc463 chore: update contributors (#6649)
Co-authored-by: Homarr Update Contributors <210161987+homarr-update-contributors[bot]@users.noreply.github.com>
2026-08-21 12:53:40 +00:00
Danura30082 73a742154e docs: Proxmox certificate obtention instructions (#6613) 2026-08-20 18:51:58 +02:00
Afonso Jorge Ramos 993a267e0c fix(truenas): keep reporting pools without usable dataset space (#6635) 2026-08-20 15:37:10 +02:00
Thomas f1c49d1fbf fix(startup): only chown runtime paths for custom PUID/PGID (#6598) 2026-08-19 08:29:17 +02:00
Thomas 95c66c61eb fix(widgets): stop Health Monitoring system tab firing NOT_FOUND when Proxmox is mixed in (#6623) 2026-08-18 19:56:47 +02:00
Thomas ec2f8c6c2c fix(widgets): match OMV disk temperature via normalized partition names (#6615) (#6619)
OMV reports filesystem devices (sda1) without the /dev/ prefix, so the
partition-suffix normalization never applied and filesystem-to-SMART
matching returned no temperature. Strip partition suffixes from
unprefixed sd/vd, nvme and mmcblk names, and use the shared normalized
matcher in both the health monitoring and system disks widgets.
2026-08-18 19:39:27 +02:00
Thomas 05ba57c2fa chore: migrate cursor rules to portable agent skills + mantine MCP guidance
* chore: migrate cursor rules to portable agent skills and add mantine MCP guidance

Replace Cursor-only .cursor/rules/*.mdc with Agent Skills open-standard
SKILL.md files in .agents/skills/ (canonical), mirrored to .cursor/skills/
and .claude/skills/ so they work across Claude Code, Cursor, Codex, and
OpenCode. Add mantine MCP server guidance to AGENTS.md and un-ignore
.agents/skills/ in .gitignore.

* refactor: single-source agent skills at .agents/skills

Cursor, Codex, and OpenCode all read .agents/skills/ natively, so the
.cursor/skills/ mirror was redundant. Claude Code reads .claude/skills/,
which is now a symlink back to .agents/skills/ so the content lives once.
Deletes .cursor/skills/ and converts .claude/skills/ to a symlink.

* chore: ship mantine MCP server via project-scoped .mcp.json

Declares the keyless @mantine/mcp-server in .mcp.json (Claude Code
project-scope standard, committable) and documents MCP server setup and
the mantine entry in AGENTS.md.

* chore: address coderabbit security-review and markdown lint findings

Add explicit security-review guidance before exposing MCP tools and label
plain-text code fences to satisfy markdownlint MD040.
2026-08-16 16:27:51 +02:00
Thomas ddbf05524b feat(http): set custom User-Agent on outbound integration requests (#6606)
* feat(http): set custom User-Agent on outbound integration requests

Set a default 'User-Agent: Homarr/<version> (+https://homarr.dev)' header
on all outbound HTTP requests made via fetchWithTrustedCertificatesAsync,
so Homarr's integration traffic is distinguishable in reverse-proxy,
WAF, and security-monitoring logs instead of appearing as generic undici.

Closes #6604

* refactor(version): centralize Homarr version in @homarr/version package

Replace fragile deep-relative 'package.json' imports across the monorepo
with a single source of truth: the new @homarr/version leaf package reads
the version once from the root package.json and exports it as VERSION.

Consumers now import by package name incl. the new User-Agent header in
fetchWithTrustedCertificatesAsync (packages/core):
  - core, api (info router), analytics, request-handler (update checker)
This also removes all manually-maintained relative version imports.

* fix(http): normalize User-Agent injection with Headers

Object-spreading fetchOptions.headers breaks when callers pass a Headers
instance (spread yields no entries) or a tuple array (numeric keys), and is
case-sensitive. Build a Headers instance and set the default User-Agent only
when no case-insensitive User-Agent entry exists, via a shared helper in both
fetch paths.

Adds unit tests covering record, Headers, tuple-array, and casing variants.

* revert(version): undo version refactor and tests, keep single-file change

Keep the User-Agent change as a single edit to
packages/core/src/infrastructure/http/request.ts. Remove the @homarr/version
package, the consumer migrations, and the unit tests.
2026-08-16 16:09:15 +02:00
Thomas df438b4cd2 Merge pull request #6571 from homarr-labs/feat/fix-home-assistant-actions 2026-08-16 00:23:14 +02:00
Thomas a1f91eb385 Merge pull request #6567 from homarr-labs/feat/fix-truenas-free-space 2026-08-15 20:20:35 +02:00
Thomas 8d5ffb2dd9 feat(paseo): add worktree install script (#6599)
* feat(paseo): add worktree install script

* feat(paseo): inline worktree setup in paseo.json

* feat(paseo): add scripts and teardown to paseo.json

* feat(paseo): expand workspace scripts catalog

* feat(paseo): reset encryption key in worktree env
2026-08-15 12:29:52 +02:00
Thomas Camlong 56e6b23af6 test(e2e): remove flaky credentials onboarding test 2026-08-15 11:05:06 +02:00
Thomas Camlong 5488bf4d18 fix(truenas): use lowercase in operator for dataset query 2026-08-15 01:33:20 +02:00
homarr-crowdin[bot] 621ea07549 chore(lang): updated translations from crowdin (#6553) 2026-08-14 20:39:02 +02:00
homarr-update-contributors[bot] f64c01456b chore: update contributors (#6588) 2026-08-14 20:38:42 +02:00
homarr-releases[bot] 56198c3f02 chore: update bug report template (#6591) 2026-08-14 20:38:26 +02:00
Thomas ca1bb6f341 Merge pull request #6592 from homarr-labs/docs/update-helm-docs
docs(helm): update chart installation page
2026-08-14 20:38:10 +02:00
github-actions[bot] bf6b6663cd docs(helm): update chart installation page 2026-08-14 18:25:32 +00:00
Releases Homarr 5c2d86767f chore(release): 1.75.0 [skip ci] 2026-08-14 17:45:24 +00:00
homarr-releases[bot] 7c75642d4d chore(release): automatic release v1.75.0 2026-08-14 17:43:56 +00:00
Thomas Camlong 7652eb8c1c preserve smart home toggle response 2026-08-13 17:04:00 +02:00
Thomas Camlong e761c10f32 fix Home Assistant widget actions 2026-08-13 16:21:48 +02:00
Thomas 2513e8454f fix: open user menu instantly (#6568) 2026-08-13 11:44:10 +02:00
ajnart f6137b2dcc fix(truenas): guard empty dataset percentage 2026-08-12 18:24:33 +02:00
ajnart 425dd90871 fix(truenas): report usable dataset space 2026-08-12 18:19:07 +02:00
Thomas 527e911eef fix(beszel): let Recharts own tooltip lifecycle (#6560) 2026-08-11 15:35:17 +02:00
Thomas ff2cdecc86 feat: rewrite image picker (#6556)
* feat: rewrite image picker

* style: auto-fix lint and format

* fix: address image picker review

* fix: preserve unicode icon searches

* test: stabilize custom widget login

* fix: suggest image searches only on create
2026-08-11 14:49:52 +02:00
Sven 742bde1d27 fix(synology): support vol_info in storage_v2 responses (#6554) 2026-08-11 08:59:28 +00:00
homarr-update-contributors[bot] 64febbce12 chore: update integrations list readme (#6551)
Co-authored-by: Homarr Update Contributors <210161987+homarr-update-contributors[bot]@users.noreply.github.com>
2026-08-10 11:44:39 +00:00
TimonandThomas 98bb1aecf8 feat(integrations): add What's Up Docker (WUD) integration and widget (#6523)
Co-authored-by: Thomas <thomas@ajnart.fr>
2026-08-10 08:42:23 +00:00
homarr-crowdin[bot]andThomas 06c489bd48 chore(lang): updated translations from crowdin (#6548)
Co-authored-by: Thomas <thomas@ajnart.fr>
2026-08-10 09:06:56 +02:00
Thomas 464d98e124 feat(settings): unify manage and board settings into a single save form (#6541) 2026-08-08 15:33:38 +02:00
Thomas 987c9ade18 fix: make internal nginx proxy tolerate disabled IPv6 (#4596) (#6539)
* fix: keep nginx IPv6 listen only when IPv6 is available (#4596)

Commit 2c48b1896 (1.45.2) made the internal nginx proxy listen on the IPv6
wildcard ('listen [::]:7575;'), which aborts nginx startup on hosts/VMs with
IPv6 disabled:

    nginx: [emerg] socket() [::]:7575 failed (97: Address family not supported by protocol)

A plain revert would reintroduce #2697 and break IPv6-only/dual-stack
environments where this listener is required. Instead, only emit the IPv6
listen directive when the host actually has IPv6 configured.

Reuse the envsubst step run.sh already performs: compute NGINX_LISTEN_IPV6
from /proc/net/if_inet6 and substitute it into the template. proc files always
report size 0, so presence is detected by grepping the file (not 'test -s').

* fix: honor HOMARR_DISABLE_IPV6 override in nginx config generation

Review feedback on #6539: give users an explicit opt-out from the IPv6
listener even when the host reports IPv6. The issue reporter (#4596)
requested such an env var, and the pattern matches the existing
ENABLE_DNS_CACHING IPv6 toggle. Auto-detection behavior is unchanged when
the var is unset. Validated in containers: override wins, dual-stack
preserved by default, IPv4-only fallback on IPv6-less hosts.
2026-08-08 11:16:49 +02:00
Sven Gottwald 6141d505e4 fix(docker): Expose TCP port in Dockerfile (#6538) 2026-08-08 08:53:50 +02:00
Thomas 6178843198 Merge pull request #6536 from homarr-labs/docs/update-helm-docs 2026-08-07 23:53:22 +02:00
github-actions[bot] a7006d746e docs(helm): update chart installation page 2026-08-07 19:37:35 +00:00
Thomas 06724cfeb2 ci: checkout repo in bot auto-merge workflows (#6535)
* ci: drop --delete-branch from reconcile auto-merge call

The reconcile job runs without a git checkout, so gh pr merge --delete-branch
fails with 'not a git repository' before enabling auto-merge. Auto-merge
itself needs no local git state; branch cleanup is already handled by the
PR-creating workflows.

* ci: checkout repo in bot auto-merge workflows

gh pr merge fails with 'not a git repository' when no checkout is present,
which prevented the reconcile job from enabling auto-merge. Restore the
checkout the previous approval workflow relied on.
2026-08-07 20:31:56 +02:00
homarr-update-contributors[bot] 131a5558b5 chore: update contributors (#6527) 2026-08-07 20:26:34 +02:00
Thomas b32ad82850 perf: cut cold route compilation and unblock preview images (#6441) 2026-08-07 20:24:26 +02:00
Thomas 622e1dcfa5 ci: drop --delete-branch from reconcile auto-merge call (#6534)
The reconcile job runs without a git checkout, so gh pr merge --delete-branch
fails with 'not a git repository' before enabling auto-merge. Auto-merge
itself needs no local git state; branch cleanup is already handled by the
PR-creating workflows.
2026-08-07 20:12:37 +02:00
homarr-releases[bot] 9674bde758 chore: update bug report template (#6533)
Co-authored-by: Releases Homarr <175486441+homarr-releases[bot]@users.noreply.github.com>
2026-08-07 18:08:24 +00:00
Thomas b479ada14f ci: auto-approve and auto-merge trusted bot pull requests (#6531)
* ci: auto-approve and auto-merge trusted bot pull requests

Replace the approve-only automatic-approval workflow with a combined
approve + enable-auto-merge workflow that also re-runs on every push,
plus a scheduled reconcile job that re-enables auto-merge for prepared
bot PRs if GitHub ever disables it. Bot PRs are gated to the known bot
actors, same-repo head, and base branch dev.

* ci: match bot authors by app slug in reconcile filter

gh pr list reports pull request authors of GitHub Apps as app/<slug>;
adjust the allowlist so the reconcile job actually matches bot PRs.
2026-08-07 20:05:46 +02:00
Releases Homarr bff3383ac9 chore(release): 1.74.0 [skip ci] 2026-08-07 17:41:07 +00:00
homarr-releases[bot] d865733838 chore(release): automatic release v1.74.0 2026-08-07 17:39:49 +00:00
homarr-crowdin[bot] 85fcea3837 chore(lang): updated translations from crowdin (#6500) 2026-08-07 18:22:43 +02:00
Thomas f76a0f240a feat(apps): allow custom URI schemes in application links (#6521) 2026-08-06 21:52:56 +02:00
Thomas 637f03e107 docs(settings): update analytics docs to PostHog (#6525) 2026-08-06 21:47:04 +02:00
Thomas 55214ccbc5 fix(integrations): throw on total item-info failure to preserve stale-cache fallback (#6522) 2026-08-06 21:42:46 +02:00
Thomas 778533a62e fix: revert regressions from recent integration/releases/app-href changes (#6514) 2026-08-03 17:37:53 +02:00
Thomas b4fba47a23 fix(releases): add success flag to successful response for correct error detection (#6512) 2026-08-03 17:10:35 +02:00
Thomas 76ddfceb13 fix: restore auto-refresh for docker and notifications widgets (#6511) 2026-08-03 17:07:46 +02:00
Thomas 2f6b96e5ba feat: restrict integrations management to integration-full-all permission (#6509) 2026-08-03 17:04:35 +02:00
Thomas f1b7a5146a fix: allow [homarr_base] template variables in app href validation (#6508) 2026-08-03 16:47:40 +02:00
Thomas Camlong 05292ae1f5 fix: map legacy media server options 2026-08-03 15:24:30 +02:00
homarr-renovate[bot] 48fc8db2b4 chore(deps): update semantic-release monorepo (major) (#6486) 2026-08-03 14:39:28 +02:00
Thomas 018f84f80d feat(dev): add Docker development CLI (#6495) 2026-08-03 14:38:56 +02:00
Thomas d58a47b776 fix: restrict system health monitoring integrations (#6505) 2026-08-02 10:17:05 +02:00
Thomas 797bdd001f fix: keep direct icon URLs visible (#6504) 2026-08-01 23:28:18 +02:00
Bergasha 49314533bf feat(Media player widget): expands on Direct Play and Transcoding badges (#6489) 2026-08-01 23:21:13 +02:00
Thomas 27ca058088 feat(widgets): persist Beszel and Docker table layouts (#6490) 2026-08-01 23:20:09 +02:00
homarr-releases[bot] f4449f9581 chore: update bug report template (#6498) 2026-08-01 23:08:14 +02:00
Thomas b52bc03c8d Merge pull request #6499 from homarr-labs/docs/update-helm-docs
docs(helm): update chart installation page
2026-08-01 23:07:58 +02:00
Thomas edb56f3fcd fix: accept direct icon URLs
Use valid direct HTTP(S) icon URLs without repository search.
2026-08-01 23:06:26 +02:00
homarr-crowdin[bot] fcc5130068 chore(lang): update translations from crowdin (#6457) 2026-07-31 23:50:10 +02:00
homarr-update-contributors[bot] c7751e293d chore: update contributors (#6496) 2026-07-31 23:49:37 +02:00
github-actions[bot] bd669a1a8f docs(helm): update chart installation page 2026-07-31 19:35:37 +00:00
Releases Homarr 9b5b79525f chore(release): 1.73.0 [skip ci] 2026-07-31 18:16:44 +00:00
homarr-releases[bot] 426929556f chore(release): automatic release v1.73.0 2026-07-31 18:15:13 +00:00
Thomas ade640dcea test(navidrome): complete cleanup review (#6494)
* test(navidrome): hoist album fixture helper

* test(navidrome): address coderabbit cleanup feedback
2026-07-31 14:39:11 +02:00
Thomas 61128ddcc8 fix(navidrome): clean up audio stats integration (#6493) 2026-07-31 14:20:51 +02:00
Thomas 6a3cee8107 fix(navidrome): complete media server session data (#6492) 2026-07-31 13:53:06 +02:00
Matt Van Horn 06d9c07d22 feat: expose Navidrome as a media-server (now-playing) integration (#6070) 2026-07-31 13:30:44 +02:00
Thomas 49d0f1a141 docs: explain Podman socket setup (#6487)
* docs: explain Podman socket setup

* docs: clarify Podman runtime requirements

* docs: complete Podman compose examples
2026-07-29 16:53:29 +02:00
Clarkar00 ac73b9d891 fix(widgets): refetch after render errors (#6399)
Remove incompatible persisted widget query data before resetting a crashed widget so it can fetch fresh data instead of re-rendering the same stale payload.
2026-07-28 23:12:03 +02:00
Thomas 489980814c Merge pull request #6465 from homarr-labs/docs/update-helm-docs
docs(helm): update chart installation page
2026-07-28 22:59:08 +02:00
Thomas 14654acced chore: gate Renovate updates behind dashboard approval (#6485) 2026-07-28 22:55:32 +02:00
Thomas 2885f7a297 fix(widgets): preserve data on integration failures (#6484) 2026-07-28 22:18:08 +02:00
Thomas 906c9f11fa feat(widgets): rework downloads widget with mantine-datatable (#6430) 2026-07-28 21:50:09 +02:00
Thomas 3419805a49 fix(beszel): restore balanced grid layout for Beszel System Grid widget (#6389) 2026-07-28 21:49:04 +02:00
homarr-releases[bot] 51a6cbe6d4 chore: update bug report template (#6464) 2026-07-28 14:56:56 +02:00
homarr-update-contributors[bot] d08eb2afa6 chore: update contributors (#6461) 2026-07-28 14:56:42 +02:00
Tim MooreandTim Moore 91a6b19ba1 fix(beszel): expire stored sessions so the integration recovers from token expiry (#6476)
Co-authored-by: Tim Moore <tim.moore@ingenuity.com.au>
2026-07-28 14:55:33 +02:00
Thomas e66979bab6 feat(auth): link credentials users with OIDC (#6445) 2026-07-28 14:49:51 +02:00
homarr-renovate[bot] 4ef7641cb2 chore(deps): update pnpm to v11.15.1 (#6466)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-25 02:43:47 +00:00
github-actions[bot] f33fc838cf docs(helm): update chart installation page 2026-07-24 21:17:32 +00:00
Releases Homarr f0019fa213 chore(release): 1.72.0 [skip ci] 2026-07-24 18:11:58 +00:00
homarr-releases[bot] ba8536b36d chore(release): automatic release v1.72.0 2026-07-24 18:10:37 +00:00
homarr-renovate[bot] 965aec5155 chore(deps): update pnpm to v11.15.0 (#6455)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-23 16:29:37 +00:00
homarr-crowdin[bot] 387db030cd chore(lang): updated translations from crowdin (#6283) 2026-07-23 09:14:14 +02:00
homarr-renovate[bot] 8e557c9924 chore(deps): update pnpm to v11.14.0 (#6449)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-23 05:58:19 +00:00
Thomas f26e60edf0 fix(old-import): map new clock weather options (#6452) 2026-07-23 02:08:50 +02:00
Thomas 7bbfd74454 Merge pull request #6384 from homarr-labs/docs/update-helm-docs
docs(helm): update chart installation page
2026-07-23 02:04:11 +02:00
homarr-releases[bot] 018b1ea4da chore: update bug report template (#6382) 2026-07-23 02:03:43 +02:00
Thomas 14c3fa2e76 fix(beszel): prevent live subscription memory growth (#6448)
* fix(beszel): bound live stats subscriptions

* fix(beszel): avoid blocking subscription teardown

* fix(import): map new clock options
2026-07-23 02:03:08 +02:00
Thomas 9168f8114b fix(manage): hide sidebar nav items from unprivileged users (#6236) 2026-07-23 02:01:10 +02:00
Thomas 9cabb42edb fix(widgets): add 350ms hover delay before opening calendar day popover (#6431) 2026-07-23 01:54:23 +02:00
Thomas bfba3c9215 fix(releases): avoid unnecessary GitHub pagination for LinuxServer updates (#6444) 2026-07-23 00:20:54 +02:00
Bergasha 7184bc09c1 feat(clock widget): Adds animated weather and temp (#6372) 2026-07-23 00:04:32 +02:00
Thomas 9bb0c0f811 fix(media-requests): cache statistics responses (#6443) 2026-07-22 17:38:28 +02:00
Thomas cf0e469465 feat: restrict apps management to board modifiers (#6425) 2026-07-21 16:56:33 +02:00
Thomas 8e7fa782b3 feat(weather): add humidity display (#6429) 2026-07-21 16:36:03 +02:00
Thomas 97652802f0 feat(immich): show random photos without album (#6424) 2026-07-21 16:10:45 +02:00
Thomas 1706289124 fix(media-server): guard against undefined playback from stale cached data (#6433) 2026-07-21 16:01:37 +02:00
homarr-renovate[bot] dd23de7aaa chore(deps): update pnpm to v11.13.1 (#6422)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-21 05:54:52 +00:00
Thomas f1602f67d4 fix: stop auto-seeding ArchiveTeam Warrior integration and widget on default dashboards (#6413) 2026-07-20 17:01:07 +02:00
Thomas c03cd97d3a fix(test): use Home Assistant long-lived token JWT
* fix(test): use Home Assistant long-lived token

* fix(test): revert to correct Home Assistant long-lived token JWT
2026-07-20 15:27:50 +02:00
Thomas a8e9a074d3 Merge pull request #6411 from homarr-labs/mysql-migration-test-timeout
fix(db): increase mysql migration test timeout to 120s
2026-07-20 15:19:12 +02:00
Thomas Camlong 1e9d3e0656 fix(db): increase mysql migration test timeout to 120s 2026-07-20 15:18:50 +02:00
Thomas 01e0f3612d docs(immich): list Asset View permission (#6408) 2026-07-20 14:57:07 +02:00
Thomas 0015a6d88d fix(immich): use thumbnail endpoint instead of original for album carousel (#6396)
* fix(immich): use thumbnail endpoint instead of original for album carousel

Switches from /api/assets/:id/original to /api/assets/:id/thumbnail to fix
HEIC image incompatibility (thumbnails are always JPEG), reduce bandwidth,
and improve loading speed.

Closes #6388

* working on immich

* Improve image proxy error handling

* fix(image-proxy): use trusted fetch response type

* docs(immich): require Asset View permission
2026-07-20 14:53:27 +02:00
Thomas 77dc317da2 chore(ci): remove memory regression tests (#6395) 2026-07-18 22:55:38 +02:00
homarr-update-contributors[bot] 6aeda3faaf chore: update contributors (#6378) 2026-07-18 22:43:01 +02:00
github-actions[bot] ac6a0c9254 docs(helm): update chart installation page 2026-07-17 19:24:43 +00:00
Releases Homarr ca358d9f8b chore(release): 1.71.0 [skip ci] 2026-07-17 17:58:17 +00:00
homarr-releases[bot] 03e0683892 chore(release): automatic release v1.71.0 2026-07-17 17:57:04 +00:00
Junker der Provinz 6ac4c6a7b9 fix(search): let public dashboards use generic custom search engines (#6375) 2026-07-17 14:53:52 +02:00
Junker der Provinz a0e0bf65ff fix(releases): let LinuxServer.io version filters find older releases via GitHub (#6376) 2026-07-17 14:53:01 +02:00
Junker der Provinz bc018e1fe0 fix(docker): disable the broken full-screen toggle on the container table (#6374) 2026-07-17 14:43:37 +02:00
Thomas 5e39c8813a feat(preferences): add enableRightClickOnWidgets user preference (#6298) 2026-07-17 14:42:19 +02:00
Thomas 06719cdef0 fix(ci): remove coverage report, scope format to changed files, fix oxlint config (#6359) 2026-07-16 10:21:07 +02:00
Bergasha 5144e14da4 fix(media-server): populate playback progress, transcode status, and network location for streams (#6315) 2026-07-15 16:27:58 +02:00
Thomas 8528d5068b feat(media-requests): filter requests list by status and time window (#6320) 2026-07-15 16:27:24 +02:00
Thomas c6c4428f7d Revert "fix(docker): report current CPU usage instead of the lifetime average" (#6357) 2026-07-15 14:55:18 +02:00
Thomas 7e4cb0201b fix(widgets): add refetchInterval to WidgetDefinition for per-widget polling (#6352) 2026-07-15 11:52:35 +02:00
Thomas 7887ce12c0 fix(integrations): resolve intermittent Seerr/Overseerr crashes and add query status to context menu (#6347) 2026-07-15 11:41:18 +02:00
Thomas 2d450239ac fix(releases): add required octokit throttling rate limit handlers (#6338) 2026-07-15 11:27:32 +02:00
Thomas bf4ccd8cb3 fix(ci): remove persist-credentials: false to fix git-auto-commit-action push (#6346) 2026-07-15 10:33:32 +02:00
homarr-renovate[bot] c473e80243 chore(deps): update pnpm to v11.11.0 (#6342)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-15 02:31:21 +00:00
homarr-renovate[bot] bf55bcce92 fix(deps): update dependency swiper to ^14.0.5 (#6341)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 23:55:02 +00:00
homarr-renovate[bot] 49248cedaf chore(deps): update dependency posthog-js to ^1.399.1 (#6340)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 22:09:52 +00:00
homarr-renovate[bot] a0034b2cfc chore(deps): update dependency @immich/sdk to ^3.0.2 (#6339)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 21:01:58 +00:00
homarr-renovate[bot] 4a297180fd chore(deps): update dependency lucide-react to ^1.24.0 (#6334)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 19:23:26 +00:00
Thomas 5fa3a3313a Merge pull request #6337 from homarr-labs/fix/ts7-nextjs-build
fix(docker): pin TypeScript to v6 to fix Next.js 16.2.10 build in CI
2026-07-14 18:11:38 +02:00
Thomas Camlong 29ee87c4aa fix(docker): pin typescript to v6 via alias to fix Next.js 16.2.10 build 2026-07-14 18:11:15 +02:00
Thomas 94a247e24a fix(docker): remove --offline flag from pnpm install step (#6335) 2026-07-14 17:19:51 +02:00
homarr-renovate[bot] 6d37710fec chore(deps): update dependency vite@>=5.0.0 <=5.4.18 to >=8.1.4 (#6333)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 11:26:55 +00:00
homarr-renovate[bot] c016beb2e5 chore(deps): update dependency vite to ^8.1.4 (#6332)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 09:06:17 +00:00
homarr-renovate[bot] f9e1b85c6a chore(deps): update dependency posthog-node to ^5.40.0 (#6314)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 06:14:41 +00:00
homarr-renovate[bot] 38ba19e665 chore(deps): update dependency oxlint to ^1.73.0 (#6306)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 03:22:16 +00:00
homarr-renovate[bot] f55c99d2d6 chore(deps): update dependency posthog-js to ^1.399.0 (#6331)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 00:00:38 +00:00
homarr-renovate[bot] c5e8b83d8a chore(deps): update vitest monorepo to ^4.1.10 (#6286)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-13 23:01:00 +00:00
homarr-renovate[bot] d52d9cfed2 chore(deps): update dependency posthog-js to ^1.398.7 (#6319)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-13 21:58:26 +00:00
Thomas 93325642aa Merge pull request #6324 from homarr-labs/renovate/major-github-artifact-actions 2026-07-13 22:12:32 +02:00
Thomas 165e94abbc Merge pull request #6328 from homarr-labs/fix-pnpm-fetch-build 2026-07-13 22:12:11 +02:00
homarr-renovate[bot] 2e3127e766 chore(deps): update docker/dockerfile docker tag to v1.25 (#6321) 2026-07-13 22:10:35 +02:00
Thomas d37326d905 Merge pull request #6322 from homarr-labs/renovate/actions-cache-6-x 2026-07-13 22:09:57 +02:00
homarr-renovate[bot] e51e39ff38 chore(deps): update dependency typescript to v7 (#6325) 2026-07-13 22:09:30 +02:00
homarr-renovate[bot] 6c075b6d74 chore(deps): update dependency mysql2 to v3.22.6 (#6310)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-13 18:45:08 +00:00
ajnart b2f63c6e0f fix(docker): drop --frozen-lockfile from install step per pnpm fetch docs
The pnpm fetch docs recommend `pnpm install -r --offline` without
--frozen-lockfile. The --offline flag already enforces no registry
access, making --frozen-lockfile redundant.

https://pnpm.io/cli/fetch
2026-07-13 20:24:59 +02:00
ajnart 8c2d73e8af fix(docker): resolve pnpm fetch crash with patchedDependencies
PR #6296 introduced pnpm fetch in the Dockerfile for Docker cache
optimization. However, pnpm fetch crashes with ENOENT when
patchedDependencies are configured with nodeLinker: hoisted because
applyPatchToDir tries to chdir into node_modules/<pkg> which doesn't
exist during fetch (only the content-addressable store is populated).

Fix: temporarily switch nodeLinker to isolated during pnpm fetch so
patches apply inside the virtual store (node_modules/.pnpm/...) which
IS created by pnpm fetch. Restore hoisted before the install step so
the final node_modules layout stays flat.

Refs: pnpm/pnpm#5268, pnpm/pnpm#8726
2026-07-13 20:06:28 +02:00
homarr-renovate[bot] 1c0ff8930e chore(deps): update actions/upload-artifact action to v7 2026-07-13 16:39:27 +00:00
homarr-renovate[bot] e2b8355639 chore(deps): update actions/cache action to v6 2026-07-13 16:39:10 +00:00
Thomas ba7718bde5 feat: rework the ci (#6296) 2026-07-13 18:32:48 +02:00
Thomas 06f1877ae1 Merge pull request #6282 from homarr-labs/docs/update-helm-docs
docs(helm): update chart installation page
2026-07-13 18:11:10 +02:00
homarr-renovate[bot] 1d9e8aabf3 chore(deps): update turbo monorepo to ^2.10.4 (#6303)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-13 13:36:45 +00:00
homarr-renovate[bot] b111e5285b chore(deps): update dependency @scalar/api-reference-react to ^0.9.54 (#6317)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-13 10:38:14 +00:00
homarr-renovate[bot] f4c491b570 chore(deps): update dependency @types/node to ^24.13.3 (#6318)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-13 10:37:23 +00:00
homarr-renovate[bot] 29bd4fd70b chore(deps): update dependency posthog-js to ^1.398.1 (#6311)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-12 18:09:44 +00:00
homarr-renovate[bot] 269dadee8d fix(deps): update dependency swiper to ^14.0.2 (#6313)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-12 18:09:11 +00:00
Thomas 03f68a0421 fix(qbittorrent): sort torrents by progress so active items appear before limit cutoff (#6297) 2026-07-12 14:56:24 +02:00
Bergasha 807e5eb2a9 feat(docker-widget): replace footer timestamp text with compact refresh button (#6307) 2026-07-12 14:51:56 +02:00
Thomas 8e8c29979f fix(system-disks): format absolute storage values with shared byte helper (#6299) 2026-07-12 14:50:58 +02:00
Manuel 7d859c1af0 docs: update pr template (#6147) 2026-07-12 14:49:56 +02:00
homarr-renovate[bot] e9543dc30d chore(deps): update tiptap monorepo to v3.27.3 (#6308)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-12 09:12:55 +00:00
Nerdy Technician 9f313440ac fix(integrations): update PatchMon API key settings link (#6302) 2026-07-12 08:59:52 +02:00
homarr-renovate[bot] c2508dffea chore(deps): update dependency posthog-js to ^1.396.7 (#6285)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-12 06:18:17 +00:00
Artur d44bc06a93 feat(notebook): support text direction controls (#6293) 2026-07-12 07:58:02 +02:00
homarr-renovate[bot] c56b91570b chore(deps): update tiptap monorepo to v3.27.2 (#6292)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-12 03:01:23 +00:00
homarr-renovate[bot] d53c4e6513 chore(deps): update dependency hono@<4.6.5 to >=4.12.28 (#6291)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-12 02:58:51 +00:00
homarr-renovate[bot] 0426d600cc chore(deps): update dependency oxfmt to ^0.58.0 (#6305)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-12 00:06:59 +00:00
Thomas 576856d634 fix(beszel): add reliable live stats and filesystem UI (#6289) 2026-07-11 17:55:04 +02:00
Thomas def3ede3bc fix(db): restore widget_secret migration journal entries accidentally removed by #6206 (#6288) 2026-07-11 15:40:06 +02:00
github-actions[bot] 34bd574354 docs(helm): Update Helm chart documentation 2026-07-10 20:32:11 +00:00
homarr-releases[bot] d9c503d01b chore: update bug report template (#6281)
Co-authored-by: Releases Homarr <175486441+homarr-releases[bot]@users.noreply.github.com>
2026-07-10 20:17:43 +00:00
Releases Homarr 82aa905214 chore(release): 1.70.0 [skip ci] 2026-07-10 20:03:12 +00:00
Thomas 4b351bb209 chore(release): automatic release v1.70.0 2026-07-10 22:01:50 +02:00
Thomas 13c9e5e181 fix(release): repair v1.70.0 quality failures (#6279)
* fix(release): repair v1.70.0 quality failures

* style: auto-fix lint and format
2026-07-10 21:59:57 +02:00
homarr-releases[bot] 6b047a9c8e chore(release): automatic release v1.70.0 2026-07-10 18:16:39 +00:00
Thomas 7a768517ef fix(request-handler): restore media organizer build (#6277) 2026-07-10 18:09:05 +02:00
Thomas 4ae8d527a8 fix(releases): token not applied due to broken allowedRepoIds check (#6276) 2026-07-10 17:55:18 +02:00
homarr-update-contributors[bot] 05a48e2930 chore: update integrations list readme (#6275) 2026-07-10 17:50:02 +02:00
Josh PrestonandThomas 33395ae226 feat(integrations): add PatchMon integration and widget (#6119)
Co-authored-by: Thomas <thomas@ajnart.fr>
2026-07-10 17:48:43 +02:00
Thomas 174c5f98f8 fix(beszel): disable request handler cache (#6274) 2026-07-10 17:40:54 +02:00
a2cf2d6cff Update Helm chart documentation (#6261)
Co-authored-by: Thomas <thomas@ajnart.fr>
Co-authored-by: Releases Homarr <175486441+homarr-releases[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-10 17:33:35 +02:00
Anil K TiwariandThomas 9fb2e37605 feat(widgets): add missing & queued media widget for Radarr and Sonarr (#6078)
Co-authored-by: Thomas <thomas@ajnart.fr>
2026-07-10 17:31:08 +02:00
homarr-crowdin[bot] 713fcd6f3f chore(lang): updated translations from crowdin (#6240) 2026-07-10 17:30:10 +02:00
homarr-update-contributors[bot] 6b10cd6874 chore: update integrations list readme (#6258) 2026-07-10 17:29:47 +02:00
homarr-update-contributors[bot] cabc66cc69 chore: update contributors (#6272) 2026-07-10 17:29:30 +02:00
Felix-AyushandThomas 2c5368dd4e feat: add Bazarr integration and subtitle status widget (#6156)
Co-authored-by: Thomas <thomas@ajnart.fr>
2026-07-10 17:29:10 +02:00
Nam NguyenandThomas 7d93df04dd fix: add utf8 email validation support (#6239)
Co-authored-by: Thomas <thomas@ajnart.fr>
2026-07-10 17:28:22 +02:00
Thomas 7c152cf4fe feat(api): expose board automation endpoints (#6213)
* feat(api): expose board automation endpoints

* style: auto-fix lint and format

* test(api): cover board settings updates

* Delete .opencode/changelog/2026-07-06.md
2026-07-10 17:27:42 +02:00
Thomas 718f095cb7 fix: prevent stale persisted query cache from blocking widget data (#6273) 2026-07-10 17:19:24 +02:00
Thomas 24c5d04bfa fix(beszel): disable request handler cache for stats to make live mode work (#6244) 2026-07-10 17:16:23 +02:00
Thomas 0e513fffd5 feat(widgets): add per-filesystem storage chart to Beszel system stats (#6209) 2026-07-10 17:08:22 +02:00
Thomas 2ada1aa249 fix(qbittorrent): handle v5 stopped torrent states for pause functionality (#6211) 2026-07-10 16:55:20 +02:00
Junker der Provinz af89423f66 fix(docker): report current CPU usage instead of the lifetime average (#6249) 2026-07-10 16:54:52 +02:00
Nerdy TechnicianandThomas 9864fed775 feat: Add Traefik Integration with dedicated widget and Add optional Icons for Gotify/Notifcation Widget (ONLY GOTIFY) (#6206)
Co-authored-by: Thomas <thomas@ajnart.fr>
2026-07-10 16:49:24 +02:00
Thomas bcd36b1b27 fix(integrations): sort media requests by last modified instead of creation date (#6264) 2026-07-10 16:46:33 +02:00
homarr-renovate[bot] a2f7b35c5c chore(deps): update pnpm to v11.10.0 (#6265)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-09 21:36:24 +00:00
homarr-renovate[bot] 616a444e64 chore(deps): update dependency @immich/sdk to ^3.0.1 (#6251)
* chore(deps): update dependency @immich/sdk to ^3.0.1

* style: auto-fix lint and format

---------

Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-09 19:51:55 +00:00
Josh Preston 65ba866239 feat: add Synology integration support for health/system monitoring (#6121) 2026-07-09 18:23:21 +02:00
Thomasandajnart 260b167134 fix: context menu refresh stays open with loading spinner, cache age reacts to refetch
* fix: context menu refresh stays open with loading spinner, cache age reacts to refetch

* style: auto-fix lint and format

* refactor: pass isFetching as prop to WidgetCacheAge to avoid duplicate useIsFetching

---------

Co-authored-by: ajnart <ajnart@users.noreply.github.com>
2026-07-07 18:39:34 +02:00
Thomas VervestandThomas 7a4de03c0e fix(integrations): accept gluetun-latest VPN settings payload (#6149)
Co-authored-by: Thomas <thomas@ajnart.fr>
2026-07-07 17:24:50 +02:00
homarr-renovate[bot] 68f8e8146b chore(deps): update dependency @scalar/api-reference-react to ^0.9.51 (#6243)
* chore(deps): update dependency @scalar/api-reference-react to ^0.9.51

* style: auto-fix lint and format

---------

Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-07 13:23:56 +00:00
Thomas 1297e6c2ac fix(query-cache): guard against undefined from superjson.parse on legacy cache entries (#6228) 2026-07-07 11:28:13 +02:00
Thomas Camlong 31288dcbfe fix(docs): update Algolia crawler config with exclusion patterns and ignoreCanonicalTo 2026-07-07 10:08:24 +02:00
Thomas fc2c251557 feat(demo): allow mutations in demo mode via DEMO_READ_ONLY flag (#6224) 2026-07-07 10:01:36 +02:00
Thomas Vervest d067261171 ci: skip lint-format-autofix on fork PRs (#6237) 2026-07-07 10:00:24 +02:00
Thomas Camlong ae2f05c834 fix(docs): sitemap priorities, exclude category redirects, remove trailingSlash 2026-07-07 09:57:32 +02:00
homarr-renovate[bot] c7fa7cdb50 chore(deps): update dependency vite@>=5.0.0 <=5.4.18 to >=8.1.3 (#6242)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-07 07:49:42 +00:00
homarr-renovate[bot] 0c28224e82 chore(deps): update nextjs monorepo to v16.2.10 (#6238)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-06 21:56:19 +00:00
homarr-renovate[bot] 4e6272dbe2 chore(deps): update dependency posthog-js to ^1.396.4 (#6232)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-06 17:56:28 +00:00
homarr-renovate[bot] f5bc090d36 chore(deps): update dependency lucide-react to ^1.23.0 (#6225)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-06 17:53:57 +00:00
homarr-renovate[bot] f23e06dff1 chore(deps): update dependency @semantic-release/github to ^12.0.9 (#6231)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-06 17:53:39 +00:00
homarr-renovate[bot] 24188ce51f chore(deps): update dependency posthog-node to ^5.39.2 (#6226)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-06 14:37:51 +00:00
homarr-renovate[bot] e31f60fdec chore(deps): update dependency cookie to v2.0.1 (#6223)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-06 14:36:14 +00:00
homarr-renovate[bot] 6bb547f3c5 chore(deps): update dependency conventional-changelog-conventionalcommits to ^10.2.0 (#6222)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-06 10:32:35 +00:00
Thomas b07cc14d0e Merge pull request #6221 from homarr-labs/feat/fix-build
fix(deps): revert typescript from 7.0.1-rc to ^6.0.3
2026-07-06 12:16:11 +02:00
Thomas Camlong 0dc93c1a02 fix(deps): revert typescript from 7.0.1-rc to ^6.0.3
Next.js 16.2.9 does not fully support TypeScript 7 (tsgo) as the
primary typescript package. The Go-native compiler has no in-process
JavaScript API — lib/typescript.js is missing — which causes Next.js's
hasNecessaryDependencies check to fail and the build to SIGABRT with
CI=true. Vercel is working on native tsgo integration expected in Q3
2026 alongside TypeScript 7 stable.
2026-07-06 12:15:38 +02:00
Thomas 00661c9b3d fix: fix pnpm lockfile (#6220) 2026-07-06 10:52:58 +02:00
Thomas 2e8fddd29f fix(docs): fix docs build — MDX acorn error and CSS @import ordering (#6217) 2026-07-06 10:14:36 +02:00
homarr-releases[bot] 302d5a0d04 chore: update bug report template (#6181) 2026-07-06 10:14:15 +02:00
ThomasandReleases Homarr a9ed95856a fix(layout): raise AppShellHeader z-index above Indicator dots (#6218)
Co-authored-by: Releases Homarr <175486441+homarr-releases[bot]@users.noreply.github.com>
2026-07-06 10:13:54 +02:00
Thomasandhomarr-renovate[bot] 4d42eb65e4 chore(deps): mega dependency update (#6212)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-06 10:05:51 +02:00
Releases Homarr 57e18f6ce6 chore(release): 1.69.2 [skip ci] 2026-07-06 08:05:24 +00:00
Thomas 29369e23c1 Merge pull request #6208 from homarr-labs/proxmox-status-zindex
fix(layout): raise AppShellHeader z-index above Proxmox status dots
2026-07-06 10:04:04 +02:00
Thomas 82858ecd75 fix(forms): break AppForm infinite render loop on edit page (#6198) (#6215) 2026-07-06 10:03:22 +02:00
homarr-crowdin[bot] 0e365ed53c chore(lang): updated translations from crowdin
* chore(lang): update translations from crowdin

* chore(lang): update translations from crowdin

---------

Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-07-06 02:04:20 +00:00
Thomas a55dc98487 Remove memory regression job from code quality workflow
Removed memory regression testing steps from the workflow.
2026-07-06 02:22:05 +02:00
ajnart 687edb9226 fix(layout): raise AppShellHeader z-index above Indicator dots
The Mantine Indicator component (used by the Proxmox cluster health
widget for VM/LXC status dots) sits at z-index 200, which is higher
than the AppShellHeader's default 100. This caused the status dots
to bleed above the header when scrolling.

Set the header z-index to 201 so it stacks above Indicator content
without conflicting with modal/popover layers (300+).

Closes #6194
2026-07-06 01:50:13 +02:00
homarr-crowdin[bot] 5b91687912 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-07-05 01:57:18 +00:00
Thomas a3df31ff05 Revise Immich API key permissions in documentation
Updated API key permissions for Immich integration documentation.
2026-07-04 21:49:08 +02:00
homarr-renovate[bot] c5c9daf5a5 chore(deps): update dependency undici to v7.28.0 [security] (#6188)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-04 18:11:47 +00:00
homarr-renovate[bot] ab0e878fbf chore(deps): update dependency posthog-js to ^1.396.2 (#6189)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-04 16:20:03 +00:00
Thomas 885be1b9a1 fix(widget-secrets): add missing widget_secret migration and add error notifications (#6192)
* fix(widget-secrets): add missing widget_secret migration and add error notifications

The widget_secret table was defined in all three Drizzle schema files but
no SQL migration was ever generated to create it, causing setSecret to
fail with 'no such table: widget_secret' in production (drizzle-kit push
in development hid the problem).

- Add migration SQL for sqlite (0040), mysql (0042), postgresql (0008)
- Update journal entries for all three dialects
- Add onError handlers to setSecret/deleteSecret mutations so errors
  are shown as red notifications instead of silently swallowed

Fixes #6186

* fix(widget-secrets): add missing drizzle snapshots for merge-url and widget_secret migrations

The merge_custom_widget_url migration (0039/0041/0007) was committed
without a corresponding snapshot, breaking drizzle-kit generate for
all future migrations. This adds:
- 0039/0041/0007 snapshots reflecting the merge-url changes
  (base_url+endpoint -> url, add enabled column)
- 0040/0042/0008 snapshots reflecting the widget_secret table

All snapshot chains now match journal entries (41/43/9 entries each).
2026-07-04 17:57:40 +02:00
homarr-renovate[bot] 0f8a86fdde fix(deps): update tailwindcss monorepo to ^4.3.2 (#6190)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-04 14:55:47 +00:00
homarr-renovate[bot] 59c084bc57 chore(deps): update testcontainers-node monorepo to ^12.0.4 (#6185)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-04 12:18:18 +00:00
homarr-renovate[bot] f6cf262bab chore(deps): update dependency posthog-js to ^1.396.1 (#6183)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-04 10:27:08 +00:00
Releases Homarr ba860aacaa chore(release): 1.69.1 [skip ci] 2026-07-04 09:02:40 +00:00
homarr-releases[bot] 161dafbdb8 chore(release): automatic release v1.69.1 2026-07-04 09:01:34 +00:00
Thomas a382c75968 fix: unblock query cache mutations in demo mode and add cache buster (#6176) 2026-07-04 10:47:09 +02:00
homarr-renovate[bot] 529942e4da chore(deps): update dependency brace-expansion@>=1.0.0 <=1.1.11 to >=5.0.7 (#6173)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-04 07:55:55 +00:00
homarr-releases[bot] e20053b2c1 chore: update bug report template (#6134) 2026-07-04 09:09:59 +02:00
134106b82c Main (#6175)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Releases Homarr <175486441+homarr-releases[bot]@users.noreply.github.com>
2026-07-04 09:09:23 +02:00
homarr-crowdin[bot] 7635031fdf chore(lang): updated translations from crowdin (#6143) 2026-07-04 08:58:20 +02:00
Bergasha b663dae409 fix (Calendar Widget): Add superjson serialization to query cache persister (#6172) 2026-07-04 08:57:49 +02:00
homarr-renovate[bot] 2c2bdb6b76 chore(deps): update dependency brace-expansion@>=2.0.0 <=2.0.1 to >=5.0.7 (#6174)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-04 04:45:04 +00:00
homarr-renovate[bot] dee9cd7aac chore(deps): update dependency lucide-react to ^1.22.0 (#6171)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-03 20:27:36 +00:00
homarr-renovate[bot] 7c222bf5e8 chore(deps): update dependency fastify to ^5.9.0 (#6166)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-03 20:26:10 +00:00
homarr-renovate[bot] f914cc26be chore(deps): update mantine monorepo to ^9.4.1 (#6165)
* chore(deps): update mantine monorepo to ^9.4.1

* style: auto-fix lint and format

---------

Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-03 20:15:37 +00:00
Releases Homarr 6f47a05cc2 chore(release): 1.69.0 [skip ci] 2026-07-03 18:08:44 +00:00
homarr-releases[bot] d8d5894b28 chore(release): automatic release v1.69.0 2026-07-03 18:07:40 +00:00
homarr-renovate[bot] 9252fdc139 fix(deps): update dependency postcss to ^8.5.16 (#6169)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-03 16:36:25 +00:00
Thomas f19033e0d5 feat: simplify caching — TanStack Query as single source of truth (#6075) 2026-07-03 16:33:03 +02:00
Thomas a5ec880eec fix(immich): v3 API compatibility — use searchAssets for album assets, drop deviceAssetId (#5977) 2026-07-03 15:59:08 +02:00
homarr-update-contributors[bot] b588672709 chore: update contributors (#6167)
Co-authored-by: Homarr Update Contributors <210161987+homarr-update-contributors[bot]@users.noreply.github.com>
2026-07-03 13:58:25 +00:00
homarr-update-contributors[bot] ceed5c6751 chore: update integrations list readme (#6085)
Co-authored-by: Homarr Update Contributors <210161987+homarr-update-contributors[bot]@users.noreply.github.com>
2026-07-02 15:47:49 +00:00
Thomas f7ede23dc3 Merge pull request #6089 from homarr-labs/feat/widget-only-integration-refactor 2026-07-02 17:37:07 +02:00
homarr-renovate[bot] 1b50249ea9 chore(deps): update dependency tar-fs@>=3.0.0 <3.0.9 to >=3.1.3 (#6162)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-02 14:11:50 +00:00
homarr-renovate[bot] 1d57519005 chore(deps): update dependency tar-fs@>=2.0.0 <2.1.3 to >=3.1.3 (#6161)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-02 11:44:07 +00:00
homarr-renovate[bot] dd2eb3aa66 chore(deps): update dependency posthog-js to ^1.395.0 (#6150)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-01 15:51:52 +00:00
Thomas Camlong 2c1a5c92e8 chore(i18n): revert non-English translations to dev
Keep translation changes in en.json only; Crowdin handles other locales.
2026-07-01 17:25:43 +02:00
ajnart 0425bec2ca style: auto-fix lint and format 2026-07-01 13:00:06 +00:00
Thomas Camlong 06da6191cc Merge origin/dev into feat/widget-only-integration-refactor
Resolve integration.ts conflict (keep widget-only documentationUrl: null, take defaultUrl from dev) and regenerate pnpm-lock.yaml.
2026-07-01 14:57:00 +02:00
homarr-renovate[bot] aec6bb18c5 chore(deps): update dependency @scalar/api-reference-react to ^0.9.49 (#6146)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-01 12:21:19 +00:00
Thomas f9da71a19b fix: quick wins — calendar, about, glances, admin UX, releases, iframe, notes (#6116) 2026-07-01 13:57:39 +02:00
homarr-renovate[bot] b83c8b6546 chore(deps): update dependency posthog-js to ^1.393.5 (#6135)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-30 21:53:10 +00:00
homarr-renovate[bot] 0e4189f693 chore(deps): update dependency dockerode to ^5.0.1 (#6130)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-30 20:09:36 +00:00
homarr-renovate[bot] 1cf010e9fb chore(deps): update node.js to v24.18.0 (#6107)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-30 18:11:58 +00:00
ajnart d670b69396 fix(timetable): restore station search by removing disabled query guard
The refactor from integration-based to option-based config changed the
useQuery enabled condition from 'integrationIds.length > 0' (always true
when an integration was linked) to 'query.length > 0'. The combination
of the debounced search value and the enabled toggle inside the nested
useOptions callback caused the query to never fire, making stations
unsearchable in the edit form.

Removing the enabled guard lets the query always run. The 300ms debounce
already prevents excessive requests.
2026-06-30 18:40:27 +02:00
Thomasandgithub-actions[bot] 7e58858353 feat(widgets): right-click context menu with auto-generated toggle actions (#6126)
* docs(helm): Update Helm chart documentation

* feat(widgets): add right-click context menu with auto-generated toggle actions

- Add WidgetContextMenu component using Mantine 9.3 Menu.ContextMenu
- Extend WidgetDefinition with contextActions API for widget-specific actions
- Auto-generate context menu toggle items for switch-type widget options
- Add 'Search' context action to media-requests widgets (list + stats)
- Keep existing dots-button menu for discoverability in edit mode
- Add widgetStateRef to WidgetComponentProps for client-side-only state
- Add skipContextMenu opt-out on switch option definitions

* style: auto-fix lint and format

* fix(widgets): address CodeRabbit review — badge in context menu target, edit-only pending gate

- Move title badge inside WidgetContextMenu wrapper so right-clicking the title overlay also triggers the context menu
- Remove full-menu hide during integration loading; only disable 'Edit' action while isPending
- Add isPending to allActions useMemo dependency array

* style: auto-fix lint and format

* fix(widgets): gate context menu behind authenticated session

- Only show right-click context menu for logged-in users
- Unauthenticated users see plain children without menu wrapper
- Matches existing BoardItemMenu session gating pattern

* style: auto-fix lint and format

* chore: revert unrelated sitemap change from auto-fix

* style: auto-fix lint and format

* fix(context-menu): persist widget option changes to server

Toggle switches and edit modal changes from the context menu now call
saveBoard mutation to persist to DB. Previously only the client cache
was updated, losing changes on reload. Removes unnecessary invalidation
that caused cascading refetch loops.

* style: auto-fix lint and format

* fix: use explicit React type imports instead of global namespace

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-30 18:10:08 +02:00
9ed55d57dd Main (#6138)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Releases Homarr <175486441+homarr-releases[bot]@users.noreply.github.com>
2026-06-30 17:52:37 +02:00
Releases Homarr 46ae756d15 chore(release): 1.68.1 [skip ci] 2026-06-30 12:02:44 +00:00
homarr-crowdin[bot] 8cac0b11c1 chore(lang): updated translations from crowdin (#6061) 2026-06-30 14:02:29 +02:00
Thomas 8b63799f1b Merge pull request #6124 from homarr-labs/fix/source-maps-memory-regression
fix: make production source maps opt-in to restore v1.67.0 memory baseline
2026-06-30 14:01:42 +02:00
homarr-renovate[bot] 5f011e8456 chore(deps): update turbo monorepo to ^2.10.0 (#6129)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-29 20:22:40 +00:00
homarr-renovate[bot] 9e1b529288 chore(deps): update dependency nanoid@>=4.0.0 <5.0.9 to >=5.1.16 (#6131)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-29 20:14:32 +00:00
homarr-renovate[bot] 4ad115dd2d chore(deps): update dependency posthog-js to ^1.393.4 (#6127)
* chore(deps): update dependency posthog-js to ^1.393.4

* style: auto-fix lint and format

---------

Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-29 20:01:36 +00:00
27209a5dde chore: add integration CODEOWNERS (#6086)
Co-authored-by: Manuel <30572287+manuel-rw@users.noreply.github.com>
Co-authored-by: Afonso Jorge Ramos <afonsojorgeramos@gmail.com>
2026-06-29 18:56:44 +02:00
ajnart 60a69e31ef fix: revert production source maps to restore v1.67.0 memory baseline
CodeRabbit review addressed:
- Removed the env-var gating (simpler: just remove source maps entirely)
- CI health check now fails fast if container never becomes healthy

Changes vs origin/main:
- next.config.ts: remove productionBrowserSourceMaps and serverSourceMaps
  (they default to false, restoring pre-v1.68.0 behavior)
- Dockerfile: remove .map copy step and NODE_OPTIONS=--enable-source-maps
- CI: add memory-regression job (<700MB guardrail)

Closes #6123
2026-06-29 15:13:08 +02:00
Thomas ed33748a49 Merge pull request #6118 from darbyjack/docs/warrior 2026-06-29 15:12:57 +02:00
ajnart 57ef0af4a2 fix: make source maps opt-in to restore v1.67.0 memory baseline
Production source maps (--enable-source-maps) caused a ~50% memory increase
(600MB to 1000MB) in v1.68.0. Node.js loads all .map files into memory when
this flag is enabled, and Next.js server chunks generate hundreds of map files.

Changes:
- Guard productionBrowserSourceMaps and serverSourceMaps behind
  HOMARR_ENABLE_SOURCE_MAPS env var (default off)
- Guard .map copy step and NODE_OPTIONS in Dockerfile behind
  ENABLE_SOURCE_MAPS build arg (default false)
- run.sh checks HOMARR_ENABLE_SOURCE_MAPS before setting --enable-source-maps
- Add Docker-based memory regression CI job (<700MB threshold)

Closes #6123
2026-06-29 10:08:52 +02:00
homarr-renovate[bot] 7a21e2a9c3 chore(deps): update dependency @playwright/test to ^1.61.1 (#6120)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 21:14:08 +00:00
darbyjack f66469d797 feat(docs): addd in documentation for archiveteam warrior 2026-06-28 15:45:52 -05:00
homarr-renovate[bot] c4a0c818d0 chore(deps): update mantine monorepo to ^9.4.0 (#6102)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 19:32:49 +00:00
homarr-renovate[bot] ef016061ae chore(deps): update pnpm to v11.9.0 (#6117)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 17:26:09 +00:00
homarr-renovate[bot] 3492700e6b chore(deps): update dependency vite to ^8.1.0 (#6114)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 14:06:36 +00:00
homarr-renovate[bot] 590d316671 chore(deps): update dependency vite@>=5.0.0 <=5.4.18 to >=8.1.0 (#6115)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 14:03:05 +00:00
homarr-renovate[bot] 6e9d20e651 chore(deps): update dependency recharts to ^3.9.0 (#6113)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 14:00:52 +00:00
homarr-renovate[bot] ed829fddfa chore(deps): update dependency posthog-js to ^1.393.0 (#6112)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 13:57:57 +00:00
Thomas Camlong 8747d5f93e fix: add id to repository schema and handle missing ids gracefully 2026-06-28 13:55:17 +02:00
homarr-renovate[bot] ed8b8a40eb chore(deps): update dependency @vitejs/plugin-react to ^6.0.3 (#6110)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 11:18:49 +00:00
homarr-renovate[bot] 7bc3bbb8c0 chore(deps): update dependency @gfazioli/mantine-onboarding-tour to ^4.0.6 (#6109)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 09:03:24 +00:00
Thomas Camlong af35a50fa0 fix: handle missing widgetSecrets table and add default releases repo
- getConfiguredKinds now returns [] if table doesn't exist yet
- Add homarr-labs/homarr as default releases repository (v#.#.#)
2026-06-28 08:47:09 +02:00
homarr-renovate[bot] 74943ef9bc chore(deps): update dependency hono@<4.6.5 to >=4.12.27 (#6108)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 05:28:04 +00:00
homarr-renovate[bot] 5dd7f839ee chore(deps): update dependency axios@>=1.0.0 <1.8.2 to >=1.18.1 (#6104)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 00:16:33 +00:00
homarr-renovate[bot] d8c6c0f978 chore(deps): update dependency posthog-js to ^1.391.4 (#6094)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 00:16:09 +00:00
homarr-renovate[bot] 75b2d1bd1b chore(deps): update dependency oxlint to ^1.71.0 (#6101)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 00:15:23 +00:00
homarr-renovate[bot] 7c12a9ce48 chore(deps): update dependency @scalar/api-reference-react to ^0.9.48 (#6103)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-28 00:13:44 +00:00
homarr-renovate[bot] 9033acc66c chore(deps): update dependency oxfmt to ^0.56.0 (#6100)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-27 22:17:27 +00:00
Thomas a42dc34d34 Revert "feat(config): enable pnpm global virtual store for worktree support" (#6106) 2026-06-27 23:37:36 +02:00
euduardo db3d58821e feat(widgets): show calendar events on hover with pin on click (#2637) (#6081)
feat(widgets): show calendar events on hover with pin on click (#2637)

docs(widgets): update calendar interactions section for hover behavior
2026-06-27 22:49:26 +02:00
Bergasha 076526293d feat(docker-widget): add per-column visibility toggle (#6093)
* Add 'Columns to show' label in Docker stats

* feat: Add column translation keys for Docker widget

* feat: Enhance table with column visibility state

Added column visibility state management for the table.

* Add 'noColumns' error message to en.json
2026-06-27 22:44:39 +02:00
Thomasandajnart 2443f1cd3f fix: dns-hole widgets showing stale disconnected state (#6096)
Co-authored-by: ajnart <ajnart@users.noreply.github.com>
2026-06-27 22:37:34 +02:00
Thomas 597b5fbc8d Merge pull request #6097 from homarr-labs/docs/update-helm-docs
Update Helm chart documentation
2026-06-27 13:24:44 +02:00
Thomas 3864727502 feat(config): enable pnpm global virtual store for worktree support (#6098) 2026-06-27 13:23:01 +02:00
github-actions[bot] 5412577519 docs(helm): Update Helm chart documentation 2026-06-27 11:22:16 +00:00
ajnart a56bf0f32d style: auto-fix lint and format 2026-06-27 11:04:33 +00:00
Thomas Camlong e687bc8c92 fix: address review - paginate GH releases, GitLab tag_name, docs, test
- Paginate GitHub releases via api.paginate to avoid missing tags beyond page 1
- Use tag_name instead of name for GitLab releases (name is a display label)
- Remove ArchiveTeam Warrior from widget-configured note in docs
- Fix test assertion to use objectContaining for error shape with message
2026-06-27 13:02:58 +02:00
Thomas Camlong 64c7512283 fix: compile versionRegex once and add fetch timeouts
- Compile regex once via compileVersionRegex, reject invalid patterns early
- Add 10s timeout to all provider fetch calls via fetchProvider wrapper
2026-06-27 12:56:48 +02:00
ajnart 398c88f2c6 style: auto-fix lint and format 2026-06-27 09:06:44 +00:00
Thomas Camlong 34d976eeea fix: apply version filter to LinuxServer.io provider
LSIO was bypassing versionRegex unlike all other providers.
2026-06-27 11:01:12 +02:00
Thomas Camlong 757d59854e fix: address PR review - atomic upsert, MCP metadata, stale tokens, save UX
- Wrap setSecret delete+insert in a cross-DB transaction
- Add MCP metadata to all widget secret procedures and register in mcp.ts
- Show configured tokens even when no repos use that provider
- Only clear token input after mutation succeeds, with loading state
2026-06-27 10:58:35 +02:00
Thomas Camlong 2155f13f24 fix: verbose error messages in all release providers
Every error now includes a diagnostic message:
- noMatchingVersion: shows the regex used, how many tags were
  checked, and sample tag names so users can see why matching failed
- noReleasesFound: distinguishes "no releases at all" from "no match"
- invalidIdentifier: shows the problematic identifier string
- unexpected: includes HTTP status codes from provider APIs

getLatestRelease returns { release } | { noMatch: reason } instead
of Release | null, carrying the diagnostic through.
2026-06-27 10:57:14 +02:00
Thomas Camlong d893515b93 fix: catch individual repo fetch failures to prevent batch crashes
Wrap each repository fetch in try/catch so one failure (Redis,
network, etc.) doesn't crash the entire query batch. Failed repos
now return a proper error response instead of causing all repos
to show "No response from provider".
2026-06-27 10:57:14 +02:00
Thomas Camlong 30107e4e76 fix: gracefully degrade when widget_secret table is missing or access denied
The releases widget was crashing because throwIfActionForbiddenAsync
or the widgetSecrets query would throw before DB migrations are run.
Wrap in try/catch so the widget works without tokens in that case.
2026-06-27 10:57:14 +02:00
ajnart 8c51a3769e style: auto-fix lint and format 2026-06-27 10:57:14 +02:00
Thomas Camlong 77884a3179 feat: add per-widget secret storage for release provider authentication
Adds encrypted token storage per release widget so users can authenticate
with GitHub, GitLab, Docker Hub, etc. without needing full integration setup.

- New `widget_secret` table (all 3 DB drivers) keyed by (itemId, kind)
- tRPC router with setSecret/deleteSecret/getConfiguredKinds (board modify access required)
- Releases router injects decrypted tokens into provider requests (board view access required)
- Tokens only used for repos matching widget's stored configuration (prevents proxy abuse)
- Provider auth: GitHub (Octokit auth), GitLab (PRIVATE-TOKEN), Docker Hub (Bearer),
  GHCR (registry token), npm (Bearer), Codeberg (token header)
- UI: "Provider Tokens" section in widget editor with PasswordInput per provider
2026-06-27 10:57:13 +02:00
ajnart d8a7477039 style: auto-fix lint and format 2026-06-27 10:57:13 +02:00
Thomas Camlong 8e1dcecf64 chore: update lockfile 2026-06-27 10:57:13 +02:00
Thomas Camlong c892731479 fix: address PR review findings for widget-only integration refactor
- Fix npm scoped package support (filter time metadata keys, make
  description optional, exclude falsy releases from version selection)
- Fix timetable date formatting (use Intl.DateTimeFormat for stable
  MM/DD/YYYY output) and named zod import
- Guard migration 0000 against unknown provider keys
- Fix migration 0003 to delete integration links by integrationId
- Reset immich album carousel index when photo list changes
- Add bounded limit to timetable router input
- Remove stale misspelled noProviderSeleceted translation key
- Fix provider name visibility in release widget settings
- Update docs: add ArchiveTeam Warrior note, fix typos, correct
  showPhotoInfo default
2026-06-27 10:57:13 +02:00
Thomas Camlong 62baaf7813 fix: update CHANGES.md for ArchiveTeam Warrior restoration, remove typo translation key 2026-06-27 10:57:13 +02:00
Thomas Camlong 8a5ad5861b fix: restore ArchiveTeam Warrior as a proper integration
The widget-only integrations refactor incorrectly removed the
ArchiveTeam Warrior integration entirely. It only needed to be
excluded from auto-seeding (by removing defaultUrl), not deleted.

This restores the integration class, reverts the widget/router/handler
to use integration middleware, and removes archiveTeamWarrior from the
widget-only-integrations migration.
2026-06-27 10:57:13 +02:00
ajnart d18d07d2f1 style: auto-fix lint and format 2026-06-27 10:57:12 +02:00
Thomas Camlong fb348044fb refactor widget-only integrations 2026-06-27 10:57:12 +02:00
homarr-releases[bot] f3608b26a0 chore: update bug report template (#6091)
Co-authored-by: Releases Homarr <175486441+homarr-releases[bot]@users.noreply.github.com>
2026-06-26 18:43:53 +00:00
Thomas 73bed51df8 fix(widgets): make downloads widget table background transparent (#6025)
The MantineReactTable defaults table cell backgrounds to
var(--mantine-color-body) which is opaque. This makes the
downloads widget table block appear solid while the footer
and other widgets correctly show the board's background.

Added a styles.css targeting table elements to force
background-color: transparent, following the same pattern
used by the beszel-system-table widget. Also added
bg=transparent to mantinePaperProps for the Paper wrapper.
2026-06-26 20:27:25 +02:00
Releases Homarr ab9aca8b60 chore(release): 1.68.0 [skip ci] 2026-06-26 18:23:57 +00:00
homarr-releases[bot] dcde2819eb chore(release): automatic release v1.68.0 2026-06-26 18:22:47 +00:00
Thomas abd16354bc feat: re-add Docker quick-access button in user menu (#6054)
Adds a Docker button to the user avatar dropdown menu (admin-only)
that opens a 1400px modal containing the same Docker container table
as /manage/tools/docker.

Closes #2165
2026-06-26 20:16:34 +02:00
homarr-update-contributors[bot] 6ac352c520 chore: update contributors (#6088)
* chore: update contributors

* style: auto-fix lint and format

---------

Co-authored-by: Homarr Update Contributors <210161987+homarr-update-contributors[bot]@users.noreply.github.com>
2026-06-26 18:14:48 +00:00
Thomas 19f9769d9e fix(manage/about): bypass self-fetch + add manage error boundary (LLM exploration) (#6009)
* fix(manage/about): bypass self-fetch to prevent ECONNREFUSED crash

The /manage/about page fetched its own API routes over HTTP
(http://$HOSTNAME:3000/api/about/...). When the server could not
reach itself (misconfigured HOSTNAME, restricted container networking,
reverse-proxy setups), fetch threw ECONNREFUSED and the whole page
crashed with a full-page Next.js error (issue #6008).

All four routes were force-static serving static JSON / a direct fs
read, so the HTTP round-trip was unnecessary. Replace the fetches
with direct JSON imports and a direct getDependenciesAsync() call,
eliminating the self-network dependency entirely.

Also add a manage-level error.tsx boundary (Next.js 16 convention) so
that any future runtime error in a manage page renders a friendly,
localised fallback inside the existing layout (sidebar stays usable)
instead of the ugly default full-page error.

Exploration draft by an LLM.

Refs #6008

* style: auto-fix lint and format

* refactor: use @static-data path alias, simplify error ternary

- Add @static-data/* tsconfig path alias to replace 7-level relative
  imports (../../../../../../../static-data/...) with clean alias
  imports across the about page and all 3 API route handlers.
- Simplify error.tsx: replace ternary with && short-circuit.
- Preserve CI lint bot's .sort() -> .toSorted() fix.

Refs #6008
2026-06-26 20:12:39 +02:00
homarr-renovate[bot] f0b2486c8a chore(deps): update dependency timezones-ical-library to ^2.2.1 (#6077)
* chore(deps): update dependency timezones-ical-library to ^2.2.1

* style: auto-fix lint and format

---------

Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-26 16:18:40 +00:00
Matt Van Horn 2443b89b46 fix(plex): use series title for media releases instead of season label (#6083) 2026-06-26 14:42:36 +02:00
Thomas 915c8a3501 fix: show app first in add item modal (#6087) 2026-06-26 14:42:13 +02:00
a2bb53a8b8 feat: add VPN status widget (#5812)
Co-authored-by: Lokesh-Kumar-Dudi <lkumardudi@gmail.com>
Co-authored-by: Thomas Camlong <thomas@ajnart.fr>
2026-06-26 14:29:23 +02:00
homarr-renovate[bot] f56a05bd8e chore(deps): update dependency video.js to ^8.23.9 (#6084)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-26 11:04:52 +00:00
homarr-renovate[bot] 6051b17401 chore(deps): update dependency nanoid@>=4.0.0 <5.0.9 to >=5.1.15 (#6079)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-25 16:37:40 +00:00
homarr-renovate[bot] 29eed08408 chore(deps): update dependency isomorphic-dompurify to ^3.18.0 (#6074)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-24 17:20:55 +00:00
homarr-renovate[bot] bd74fe4a61 chore(deps): update dependency posthog-js to ^1.391.0 (#6073)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-24 17:18:43 +00:00
homarr-renovate[bot] b88e8861e1 chore(deps): update dependency rollup@>=4.0.0 <4.22.4 to >=4.62.1 (#6076)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-24 17:17:34 +00:00
homarr-renovate[bot] 39af3ec7e6 chore(deps): update dependency mantine-datatable to ^9.3.1 (#6072)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-24 17:17:15 +00:00
homarr-renovate[bot] 7f50be3dbb chore(deps): update dependency fast-xml-parser to ^5.9.3 (#6069)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-24 14:48:29 +00:00
homarr-renovate[bot] b6b7bea1dd chore(deps): update dependency mantine-contextmenu to ^9.3.1 (#6071)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-24 11:56:45 +00:00
homarr-renovate[bot] 9bde1dfbd6 chore(deps): update dependency pg to ^8.22.0 (#6068)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-24 04:26:21 +00:00
homarr-renovate[bot] c2712ed7f1 chore(deps): update tiptap monorepo to v3.27.1 (#6067)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-23 22:24:52 +00:00
homarr-renovate[bot] 16be7ece33 chore(deps): update dependency nanoid@>=4.0.0 <5.0.9 to >=5.1.14 (#6066)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-23 20:19:16 +00:00
homarr-renovate[bot] b0a46186d1 chore(deps): update node.js to v24.17.0 (#6043)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-23 18:07:27 +00:00
homarr-renovate[bot] d0385a4480 chore(deps): update dependency @ctrl/qbittorrent to ^9.13.0 (#5978)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-23 18:06:38 +00:00
homarr-renovate[bot] 3d6a3594a3 chore(deps): update pnpm to v11.8.0 (#6064)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-23 16:02:26 +00:00
homarr-renovate[bot] 641ee18278 chore(deps): update dependency hono@<4.6.5 to >=4.12.26 (#6062)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-23 12:44:43 +00:00
homarr-renovate[bot] 2e538bf40d chore(deps): update dependency lucide-react to ^1.21.0 (#6063)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-23 09:52:42 +00:00
homarr-renovate[bot] 1c0a94a6dc chore(deps): update playwright monorepo (#6045)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-23 00:26:23 +00:00
homarr-renovate[bot] 3a3dc449de chore(deps): update scalar monorepo (#6056)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-23 00:22:43 +00:00
homarr-renovate[bot] d6b156b8ee chore(deps): update dependency posthog-js to ^1.388.1 (#6041)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-23 00:21:38 +00:00
homarr-renovate[bot] fc4e31fb42 chore(deps): update dependency @gfazioli/mantine-onboarding-tour to ^4.0.5 (#6033)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-23 00:19:54 +00:00
homarr-renovate[bot] b82b22431b chore(deps): update vitest monorepo to ^4.1.9 (#6037)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 22:15:25 +00:00
homarr-renovate[bot] 510cba295a chore(deps): update dependency oxfmt to ^0.55.0 (#6040)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 19:49:24 +00:00
homarr-renovate[bot] 56d838dafc chore(deps): update dependency fast-xml-parser to ^5.9.2 (#6039)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 19:45:28 +00:00
homarr-renovate[bot] eae9f0438c chore(deps): update oxlint monorepo (#6044)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 16:17:14 +00:00
homarr-renovate[bot] b81f729bfd chore(deps): update testcontainers-node monorepo to ^12.0.3 (#6057)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 16:07:28 +00:00
homarr-renovate[bot] 86b83c5425 chore(deps): update mantine monorepo to ^9.3.2 (#6036)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 16:05:35 +00:00
Thomas bbc4589c9e fix(beszel): leverage TanStack Query for stale-while-revalidate caching (#6055) 2026-06-22 17:17:09 +02:00
Thomas ea9dd716f0 Merge pull request #6053 from homarr-labs/beszel-1w-30d-data-view
fix(beszel): use 480m interval for 1w/30d stats views
2026-06-22 15:44:43 +02:00
Thomas Camlong 4383da38ef fix(beszel): use 480m interval for 1w/30d stats views
Beszel only stores stats at 1m, 10m, 20m, 120m, 480m intervals.
The 1440m type doesn't exist, so queries for 1w/30d returned empty
results. Use 480m (8h) with appropriate perPage (21 for 1w, 90 for 30d).
2026-06-22 15:44:14 +02:00
homarr-crowdin[bot] 58cb65cb3a chore(lang): updated translations from crowdin (#6029) 2026-06-22 15:23:27 +02:00
Matt Van Horn 89380f81dd feat: ship source maps for readable production stack traces (#6031) 2026-06-22 15:22:54 +02:00
Thomas e01571b221 fix(icon-picker): keep URL visible in edit mode, add SVG-first ordering (#6051) 2026-06-22 15:22:25 +02:00
Thomasandajnart 49c266374d fix(beszel): harden cache layer and prevent blank widgets (#6052)
* fix(beszel): harden cache layer and prevent blank widgets

- Add debug logging across Beszel integration, request handler, and tRPC
  router (auth, fetch, SSE, per-procedure entry/exit) gated behind
  LOG_LEVEL=debug
- cached-request-handler: retry with backoff, isValid predicate to skip
  caching invalid data, in-flight dedup (single-flight per channel) to
  avoid thundering herd after cache invalidation
- redis channel: set-then-publish so storage is always consistent even
  when pubsub publish fails
- Beszel handlers: opt into fallbackToStaleOnError and retry so brief
  upstream hiccups don't throw away good cached data
- beszel-system-stats: add refetchInterval matching each time period's
  cache TTL so historical charts refresh in the background
- tRPC router: switch Promise.all -> Promise.allSettled for getSystems
  and getAlerts; getSystemStats returns an error object instead of
  throwing. Each result carries an optional error field so one failed
  integration no longer nukes the whole widget
- Widgets: add explicit isPending loader, empty state for grid and
  stats, and a shared per-integration error indicator (tooltip with
  failed integration names). Alerts and table now only show their
  empty state after loading completes
- Translation: add empty.noSystems key to beszelSystemGrid and
  beszelSystemStats

Addresses #6030

* style: auto-fix lint and format

---------

Co-authored-by: ajnart <ajnart@users.noreply.github.com>
2026-06-22 15:20:12 +02:00
homarr-renovate[bot] 577950d20e chore(deps): update tiptap monorepo to v3.27.0 (#6047)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 11:10:10 +00:00
homarr-renovate[bot] 82bf71b073 chore(deps): update pnpm to v11.7.0 (#6046)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 11:08:43 +00:00
homarr-renovate[bot] e26883acfa chore(deps): update lucide monorepo (#6042)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 11:05:29 +00:00
homarr-renovate[bot] 8ee747cde8 chore(deps): update dependency axios@>=1.0.0 <1.8.2 to >=1.18.0 (#6038)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 10:57:58 +00:00
homarr-renovate[bot] faa7e55b1b chore(deps): update dependency video.js to ^8.23.8 (#6035)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 10:50:43 +00:00
homarr-renovate[bot] ce021a89ac chore(deps): update dependency posthog-node to ^4.18.0 (#6034)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-06-22 10:50:04 +00:00
Thomas 55fb227305 fix(beszel): improve stats date display, add click-to-stats modal, fix grid ordering (#6026) 2026-06-20 15:38:04 +02:00
Thomas 39e424563a fix(beszel): widget transparency, error handling, and cache invalidation (#5993) 2026-06-20 12:21:26 +02:00
Afonso Jorge Ramos e29c79a902 fix(widgets): clean up health monitoring disk and size display (#6019) 2026-06-20 11:47:38 +02:00
Afonso Jorge Ramos a19c9d88ca fix(widgets): hide system disk usage value when it overflows and show it in a tooltip (#6022) 2026-06-20 11:45:39 +02:00
Afonso Jorge Ramos 1fb97ee9c6 fix(unraid): report disk free space instead of total size (#6018) 2026-06-20 10:12:11 +02:00
Afonso Jorge Ramos f69e545d64 fix(truenas): report actual memory usage and pool free space (#6017) 2026-06-20 10:11:12 +02:00
Afonso Jorge Ramos 52df56b19d fix(widgets): hide health monitoring default tab option for non-proxmox integrations (#6021) 2026-06-20 08:14:56 +02:00
Afonso Jorge Ramos 0f66bfd6c1 fix(integrations): prevent certificate trust button from submitting the form (#6020) 2026-06-20 07:46:36 +02:00
Thomas 842c5a0b4c Merge pull request #6013 from homarr-labs/chore/update-cron 2026-06-20 07:27:19 +02:00
homarr-crowdin[bot] ce9134dee2 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-06-20 02:14:01 +00:00
homarr-releases[bot] 9ce9be6b7e chore: update bug report template (#6015)
Co-authored-by: Releases Homarr <175486441+homarr-releases[bot]@users.noreply.github.com>
2026-06-19 20:44:05 +00:00
Releases Homarr 7ec22411a6 chore(release): 1.67.0 [skip ci] 2026-06-19 20:27:41 +00:00
homarr-releases[bot] d3ae06e515 chore(release): automatic release v1.67.0 2026-06-19 20:26:34 +00:00
Manuel d09a4f8468 chore: update cron 2026-06-19 22:08:25 +02:00
Thomas Camlong bcaa93f90b chore: trigger release build for v1.66.1 2026-06-18 13:39:22 +02:00
Thomas Camlong eef06dd5a3 Revert "chore(release): 1.66.0 [skip ci]"
This reverts commit 84e044f427.
2026-06-18 13:17:30 +02:00
Releases Homarr 84e044f427 chore(release): 1.66.0 [skip ci] 2026-06-18 11:14:43 +00:00
homarr-releases[bot] 609ab9976a chore(release): automatic release v1.66.0 2026-06-18 11:13:29 +00:00
Thomas Camlong 28f570aa79 Revert "chore(release): 1.66.0 [skip ci]"
This reverts commit 5b4f03da35.
2026-06-18 13:07:44 +02:00
Releases Homarr 5b4f03da35 chore(release): 1.66.0 [skip ci] 2026-06-18 10:55:09 +00:00
921 changed files with 130431 additions and 65456 deletions

No files matched your search

@@ -1,6 +1,6 @@
---
description: Comprehensive Homarr codebase architecture and conventions reference
alwaysApply: true
name: codebase-context
description: Comprehensive Homarr codebase architecture and conventions reference. Use when orienting in the monorepo, understanding package dependency layers, the three runtime services and ports, tRPC router structure, multi-database support, widget/integration/cron system architecture, routing, auth providers, env vars, or key patterns before writing code.
---
# Homarr Codebase Context
@@ -27,7 +27,7 @@ Homarr is an open-source, self-hosted dashboard for managing homelab services. I
## Repository Structure
```
```text
homarr/
├── apps/
│ ├── nextjs/ # Main Next.js application (port 3000)
@@ -66,8 +66,6 @@ homarr/
│ ├── analytics/ # Server-side analytics (Umami)
│ ├── server-settings/ # Server setting keys/types
│ ├── settings/ # User-facing settings UI context
│ ├── old-import/ # Legacy Homarr import
│ ├── old-schema/ # Legacy Homarr zod schemas
│ └── cli/ # Node CLI for ops (brocli)
├── tooling/
│ ├── typescript/ # Base tsconfig
@@ -79,11 +77,11 @@ homarr/
## Three Runtime Services
| Service | Port | Role |
|---------|------|------|
| Next.js | 3000 | Main web app (SSR + API routes) |
| WebSocket | 3001 | tRPC subscriptions via `ws` |
| Tasks | 3002 | Cron job runner + management API via Fastify |
| Service | Port | Role |
| --------- | ---- | -------------------------------------------- |
| Next.js | 3000 | Main web app (SSR + API routes) |
| WebSocket | 3001 | tRPC subscriptions via `ws` |
| Tasks | 3002 | Cron job runner + management API via Fastify |
In Docker, nginx listens on **7575** and proxies to all three. The tasks service authenticates via `CRON_JOB_API_KEY` header.
@@ -112,6 +110,7 @@ In Docker, nginx listens on **7575** and proxies to all three. The tasks service
### Multi-Database Support
Drizzle schemas exist in three parallel implementations:
- `packages/db/schema/sqlite.ts`
- `packages/db/schema/mysql.ts`
- `packages/db/schema/postgresql.ts`
@@ -121,6 +120,7 @@ Selected at runtime via `DB_DRIVER` env (`better-sqlite3` | `mysql2` | `node-pos
### Widget System
Widgets are registered in `packages/widgets/src/index.tsx` as `widgetImports` (must satisfy `Record<WidgetKind, ...>`). Each widget:
- Has a `definition` created via `createWidgetDefinition(kind, { icon, createOptions, supportedIntegrations? })`
- Uses `optionsBuilder.from(factory => ({ ... }))` for typed options
- Loads dynamically via `next/dynamic`
@@ -133,6 +133,7 @@ Integrations are defined in `packages/definitions/src/integration.ts` (`integrat
### Cron Job System
Jobs defined in `packages/cron-jobs/src/jobs/`. Each job:
- Uses `createCronJob` with a cron expression
- Publishes results to Redis channels
- Widget subscriptions consume those channels via tRPC subscriptions
@@ -160,6 +161,7 @@ Configured via `AUTH_PROVIDERS` env. Supports: `credentials` (local), `ldap`, `o
## Environment Variables
Key env vars (from `.env.example`):
- `DB_DRIVER`: `better-sqlite3` | `mysql2` | `node-postgres`
- `DB_URL`: Database connection string
- `AUTH_SECRET`: NextAuth secret
@@ -191,16 +193,3 @@ Key env vars (from `.env.example`):
- Drag-and-drop via `@dnd-kit/*`
- `typescript.ignoreBuildErrors: true` in next.config (types checked separately via `typecheck`)
- `serverExternalPackages`: `dockerode`, `isomorphic-dompurify`, `jsdom`
## Documentation (`apps/docs`)
Docusaurus 3 site at `apps/docs/`, package name `@homarr/docs`.
- Run with `pnpm dev:docs` from root
- Build with `pnpm turbo build --filter=@homarr/docs`
- Uses Tailwind CSS 3 for custom pages (not Mantine)
- Imports `@homarr/definitions` for type-safe integration/widget metadata
- When adding or modifying widgets, integrations, cron jobs, API routes, env vars, or user-facing features, you MUST also update corresponding docs in `apps/docs/docs/`
- Integration docs: `apps/docs/docs/integrations/<slug>/index.mdx` + `index.ts`
- Widget docs: `apps/docs/docs/widgets/<slug>/index.mdx` + `index.ts`
- Strict link checking: broken links/anchors cause build failure
+691
View File
@@ -0,0 +1,691 @@
---
name: datatable-migration
description: Playbook for migrating tables from mantine-react-table (MRT) to mantine-datatable. Use when converting any table component from mantine-react-table to mantine-datatable, working on DataTable column/sort/expansion/context-menu code, or implementing responsive column visibility, column persistence, or transparent tables in widgets.
---
# Migrating Tables from mantine-react-table to mantine-datatable
This document captures every pattern, fix, and decision from the downloads widget rework (PR #6430). Use it as a playbook when porting other tables.
## Migration Candidates
Current `mantine-react-table` consumers that could be migrated:
**Widgets (in `packages/widgets/`):**
- `docker/component.tsx` — Docker container table
- `media-server/component.tsx` — Media server sessions
**Admin pages (in `apps/nextjs/src/app/[locale]/manage/`):**
- `tools/docker/docker-table.tsx`
- `tools/tasks/_components/tasks-table.tsx`
- `tools/api/components/api-keys.tsx`
- `users/_components/user-list.tsx`
- `users/invites/_components/invite-list.tsx`
- `tools/kubernetes/` — 8 Kubernetes resource tables
**Modals:**
- `packages/modals-collection/src/search-engines/request-media-modal.tsx`
**Shared hook to remove once all migrated:**
- `packages/ui/src/hooks/use-translated-mantine-react-table.ts`
## 1. Core Migration: mantine-react-table → mantine-datatable
### Import changes
```typescript
// BEFORE
import { MantineReactTable, useMantineReactTable } from "mantine-react-table";
import type { MRT_ColumnDef } from "mantine-react-table";
// AFTER
import { DataTable, useDataTableColumns } from "mantine-datatable";
import type { DataTableColumn, DataTableSortStatus } from "mantine-datatable";
```
### Column definition shape
```typescript
// BEFORE (MRT)
const columns: MRT_ColumnDef<MyRow>[] = [
{
accessorKey: "name",
header: "Name",
size: 200,
enableSorting: true,
Cell: ({ row }) => <Text>{row.original.name}</Text>,
},
];
// AFTER (mantine-datatable)
const columns: DataTableColumn<MyRow>[] = [
{
accessor: "name", // not accessorKey
title: "Name", // not header
width: 200, // not size
sortable: true, // not enableSorting
render: (record) => <Text>{record.name}</Text>, // not Cell
},
];
```
Key differences:
- `accessorKey` → `accessor`
- `header` → `title`
- `size` → `width`
- `Cell: ({ row }) =>` → `render: (record) =>`
- `enableSorting` → `sortable`
- `enableColumnActions` → does not exist (no column action menus)
- `mantineTableBodyCellProps` → `cellsStyle` in `defaultColumnProps`
### Table component
```typescript
// BEFORE
const table = useTranslatedMantineReactTable({ columns, data, ... });
return <MantineReactTable table={table} />;
// AFTER
return (
<DataTable
records={data}
columns={columns}
sortStatus={sortStatus}
onSortStatusChange={setSortStatus}
...
/>
);
```
### Sorting is manual
mantine-datatable does NOT sort for you. You must sort the data yourself:
```typescript
const [sortStatus, setSortStatus] = useState<DataTableSortStatus<MyRow>>({
columnAccessor: "name",
direction: "asc",
});
const sortedData = useMemo(() => {
const mult = sortStatus.direction === "desc" ? -1 : 1;
return [...data].toSorted((a, b) => {
const aVal = a[sortStatus.columnAccessor];
const bVal = b[sortStatus.columnAccessor];
if (typeof aVal === "string") return aVal.localeCompare(bVal as string) * mult;
return ((aVal as number) - (bVal as number)) * mult;
});
}, [data, sortStatus]);
// Pass sortedData to records, not data
<DataTable records={sortedData} sortStatus={sortStatus} onSortStatusChange={setSortStatus} />
```
## 2. Making Tables Transparent (Widget Context)
Widgets sit inside board cards that have user-controlled opacity. The table must be fully transparent so the card background shows through. mantine-datatable defaults to `var(--mantine-color-body)` which is opaque.
Create a CSS file alongside the component:
```css
/* styles.css */
.my-table,
.my-table .mantine-datatable-table,
.my-table .mantine-datatable-table thead,
.my-table .mantine-datatable-table tbody,
.my-table .mantine-datatable-table tfoot,
.my-table th,
.my-table td {
background-color: transparent !important;
}
.my-table .mantine-datatable-table tr {
background-color: transparent;
}
/* Hover: translucent instead of opaque */
.my-table .mantine-datatable-table tbody tr:hover {
background-color: color-mix(
in srgb,
var(--mantine-color-default-hover) 40%,
transparent
) !important;
}
/* Headers: frosted glass effect */
.my-table th {
white-space: nowrap;
background-color: color-mix(
in srgb,
var(--mantine-color-body) 60%,
transparent
) !important;
backdrop-filter: blur(8px);
}
/* Cell overflow */
.my-table td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Hide sort icon until hover */
.my-table .mantine-datatable-header-cell-sortable-icon {
opacity: 0;
transition: opacity 150ms;
}
.my-table th:hover .mantine-datatable-header-cell-sortable-icon {
opacity: 1;
}
/* Row expansion area */
.my-table .mantine-datatable-row-expansion-cell {
background-color: color-mix(
in srgb,
var(--mantine-color-body) 40%,
transparent
) !important;
}
```
Import it: `import "./styles.css";` and apply via `className="my-table"`.
## 3. Responsive Column Visibility
Use a lookup table of width breakpoints instead of media queries. The widget receives `width` as a prop.
```typescript
interface SizeConfig {
fontSize: "xs" | "sm";
iconSize: number;
cellPadding: number;
showSpeedColumns: boolean;
showTimeColumn: boolean;
showStateColumn: boolean;
}
const SIZE_BREAKPOINTS: { maxWidth: number; config: SizeConfig }[] = [
{
maxWidth: 300,
config: {
fontSize: "xs",
iconSize: 12,
cellPadding: 2,
showSpeedColumns: false,
showTimeColumn: false,
showStateColumn: false,
},
},
{
maxWidth: 500,
config: {
fontSize: "xs",
iconSize: 14,
cellPadding: 4,
showSpeedColumns: false,
showTimeColumn: true,
showStateColumn: false,
},
},
];
const DEFAULT_SIZE_CONFIG: SizeConfig = {
fontSize: "sm",
iconSize: 14,
cellPadding: 4,
showSpeedColumns: true,
showTimeColumn: true,
showStateColumn: true,
};
function getSizeConfig(width: number): SizeConfig {
for (const { maxWidth, config } of SIZE_BREAKPOINTS) {
if (width < maxWidth) return config;
}
return DEFAULT_SIZE_CONFIG;
}
// Usage: memoize it
const size = useMemo(() => getSizeConfig(width), [width]);
```
Then use a visibility check lookup table for columns:
```typescript
const columnVisibilityChecks: Partial<
Record<string, (ctx: ColumnContext) => boolean>
> = {
upSpeed: (ctx) => ctx.hasTorrents && ctx.size.showSpeedColumns,
downSpeed: (ctx) => ctx.size.showSpeedColumns,
time: (ctx) => ctx.size.showTimeColumn,
state: (ctx) => ctx.size.showStateColumn,
};
function shouldIncludeColumn(accessor: string, ctx: ColumnContext): boolean {
if (!ctx.optionsColumnSet.has(accessor)) return false;
const check = columnVisibilityChecks[accessor];
if (check && !check(ctx)) return false;
return true;
}
```
## 4. Column Persistence (Drag/Resize → Server)
`useDataTableColumns` stores column order and widths in localStorage by default. For widgets, this must persist server-side so it works across devices.
### Hidden widget options
In `index.ts`, add hidden text options:
```typescript
columnOrder: factory.text({ defaultValue: "" }),
columnWidths: factory.text({ defaultValue: "" }),
```
With visibility override:
```typescript
{
columnOrder: { shouldHide: () => true },
columnWidths: { shouldHide: () => true },
}
```
### Translation keys required
Even hidden options need translation keys or the translation test fails:
```json
"widget.mywidget.option.columnOrder.label": "Column order",
"widget.mywidget.option.columnWidths.label": "Column widths"
```
### Dynamic storeKey
Use a key that includes `itemId` and sorted column names. This prevents cross-widget localStorage bleeding:
```typescript
const storeKey = `mytable-${itemId ?? "preview"}-${[...options.columns].toSorted().join(",")}`;
```
### Hydration from server → localStorage
On mount, seed `useDataTableColumns` with server-persisted values. Use a `hydrated` ref to prevent the persist effect from immediately writing defaults back:
```typescript
const {
effectiveColumns,
columnsOrder,
columnsWidth,
setColumnsOrder,
setMultipleColumnWidths,
} = useDataTableColumns<MyRow>({ key: storeKey, columns });
const lastStoreKey = useRef(storeKey);
const hydrated = useRef(false);
useEffect(() => {
if (lastStoreKey.current !== storeKey) {
lastStoreKey.current = storeKey;
hydrated.current = false;
}
if (hydrated.current) return;
if (savedOrder.length > 0) setColumnsOrder(savedOrder);
if (Object.keys(savedWidths).length > 0) {
setMultipleColumnWidths(
Object.entries(savedWidths).map(([accessor, w]) => ({
accessor,
width: w,
})),
);
}
requestAnimationFrame(() => {
hydrated.current = true;
});
}, [
storeKey,
savedOrder,
savedWidths,
setColumnsOrder,
setMultipleColumnWidths,
]);
```
### Persist localStorage → server
Watch for changes and write back:
```typescript
const prevOrder = useRef(columnsOrder);
const prevWidths = useRef(columnsWidth);
useEffect(() => {
if (!hydrated.current) return;
const orderChanged =
JSON.stringify(columnsOrder) !== JSON.stringify(prevOrder.current);
const widthsChanged =
JSON.stringify(columnsWidth) !== JSON.stringify(prevWidths.current);
prevOrder.current = columnsOrder;
prevWidths.current = columnsWidth;
if (!orderChanged && !widthsChanged) return;
if (orderChanged)
persistOption({ columnOrder: JSON.stringify(columnsOrder) });
if (widthsChanged) {
const widthMap: Record<string, number> = {};
for (const entry of columnsWidth) {
const key = Object.keys(entry)[0];
if (!key) continue;
const v = entry[key as keyof typeof entry];
if (typeof v === "number") widthMap[key] = v;
else if (typeof v === "string" && v.endsWith("px"))
widthMap[key] = parseInt(v, 10);
}
persistOption({ columnWidths: JSON.stringify(widthMap) });
}
}, [columnsOrder, columnsWidth, persistOption]);
```
The `persistOption` helper calls both `setOptions` (local state) and `saveItemOptions` (server mutation).
## 5. Context Menu (Right-Click)
Do NOT install `mantine-contextmenu`. Use Mantine's `Menu` + `Portal` directly:
```typescript
interface ContextMenuState {
x: number;
y: number;
item: MyRow;
}
const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);
const handleContextMenu = useCallback(
({ record, event }: { record: MyRow; event: React.MouseEvent }) => {
event.preventDefault();
setContextMenu({ x: event.clientX, y: event.clientY, item: record });
},
[],
);
// On DataTable:
<DataTable onRowContextMenu={handleContextMenu} />
// Render:
{contextMenu && <RowContextMenu state={contextMenu} onClose={closeContextMenu} />}
```
The menu component uses `Portal` for correct z-index:
```tsx
function RowContextMenu({
state,
onClose,
}: {
state: ContextMenuState;
onClose: () => void;
}) {
return (
<Portal>
<Menu
opened
onClose={onClose}
closeOnItemClick={false}
position="right-start"
offset={0}
>
<Menu.Target>
<Box
style={{
position: "fixed",
left: state.x,
top: state.y,
width: 0,
height: 0,
}}
/>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item
onClick={() => {
/* action */ onClose();
}}
>
Action
</Menu.Item>
</Menu.Dropdown>
</Menu>
</Portal>
);
}
```
**Key fix:** Use `closeOnItemClick={false}` if any menu item needs a two-step confirmation (like delete → confirm). Close the menu on scroll: `onScroll={() => { if (contextMenu) closeContextMenu(); }}`.
## 6. Row Expansion
```typescript
<DataTable
rowExpansion={{
trigger: "click",
allowMultiple: true,
collapseProps: {
transitionDuration: 200,
animateOpacity: true,
transitionTimingFunction: "ease-out",
},
content: ({ record, collapse }) => <ExpandedRow item={record} collapse={collapse} />,
}}
/>
```
**Critical:** Do NOT set `onRowClick` when using `rowExpansion` with `trigger: "click"`. They conflict and the expansion won't work.
## 7. Common Pitfalls & Fixes
### Status indicator dots
Don't use `<Badge variant="dot" />` without children — it renders a pill with empty space. Use a plain `Box`:
```tsx
<Box
w={8}
h={8}
style={{
borderRadius: "50%",
backgroundColor: `var(--mantine-color-${color}-filled)`,
flexShrink: 0,
}}
/>
```
### Tooltip overflow on long text columns
When a column has `ellipsis: true`, the tooltip target element can still extend beyond the cell bounds if inner elements don't clip. Fix:
```tsx
<Tooltip position="bottom-start" ...>
<Group style={{ overflow: "hidden" }}>
...
</Group>
</Tooltip>
```
Use `position="bottom-start"` instead of `position="right"` so the tooltip never escapes the widget horizontally.
### Dark mode tooltips
Mantine tooltips default to the theme's tooltip color which may be white in light mode and stay white in dark mode. Always set `color="dark"` on informational tooltips inside widgets.
### Division by zero
Guard all ratio calculations:
```typescript
if (item.size > 0) ratio = item.sent / item.size;
if (totalDown > 0) ratio = totalUp / totalDown;
```
### Composite idAccessor
When rows can come from multiple integrations, IDs may collide. Use a composite key:
```typescript
idAccessor={(record) => `${record.integration.id}:${record.id}`}
```
### JSON option parsing
Always wrap in try/catch:
```typescript
function parseJsonOption<T>(value: string | undefined, fallback: T): T {
if (!value) return fallback;
try {
return JSON.parse(value) as T;
} catch {
return fallback;
}
}
```
### Clipboard API
`navigator.clipboard.writeText()` can throw in non-HTTPS contexts. Always catch:
```typescript
void navigator.clipboard.writeText(text).catch(() => {});
```
### Sync sortStatus with widget options
If the widget has configurable default sort, sync it:
```typescript
useEffect(() => {
setSortStatus({
columnAccessor: options.defaultSort,
direction: defaultSortDirection,
});
}, [options.defaultSort, defaultSortDirection]);
```
## 8. Accessibility
- All `ActionIcon` components need `aria-label`
- Filter toggles (client badges, status badges) need `aria-pressed={isActive}`
- `textSelectionDisabled` on DataTable prevents accidental text selection during drag/resize
## 9. Error Handling
- Every mutation needs an `onError` callback with `showErrorNotification`
- The `saveItemOptions` mutation (column persistence) also needs `onError`
- Check `isError` on the main query and show a fallback UI
- Use a shared `mutationOptions` object to avoid repeating `onSettled`/`onError`:
```typescript
const mutationOptions = {
onSettled: () => void utils.myQuery.invalidate(),
onError: () =>
showErrorNotification({
title: t("errors.actionFailed"),
message: t("errors.actionFailedMessage"),
}),
};
```
## 10. i18n
- No hardcoded strings. Every user-visible string goes through `useScopedI18n`
- Column titles: `t("items.{accessor}.columnTitle")`
- Detail labels: `t("items.{accessor}.detailsTitle")`
- States: `t("states.{state}")`
- Actions: `t("actions.{action}")`
- Errors: `t("errors.{errorKey}")`
- Hidden options still need `.label` translation keys
## 11. Edit Mode
Disable pointer events on the table during edit mode to prevent conflicts with the board's drag-and-drop:
```typescript
let tablePointerEvents: React.CSSProperties["pointerEvents"];
if (isEditMode) tablePointerEvents = "none";
let rowContextMenuHandler = handleContextMenu;
if (isEditMode) rowContextMenuHandler = undefined;
<DataTable style={{ pointerEvents: tablePointerEvents }} />
```
## 12. DataTable Props Reference (Commonly Used)
```typescript
<DataTable
records={sortedData}
columns={effectiveColumns}
storeColumnsKey={storeKey}
withTableBorder={false}
borderRadius={0}
highlightOnHover
striped="odd"
stripedColor={{ dark: "dark.7", light: "gray.0" }}
highlightOnHoverColor={{ dark: "dark.5", light: "gray.1" }}
verticalAlign="center"
fetching={isFetching && data.length === 0}
loaderBackgroundBlur={2}
fz={size.fontSize}
textSelectionDisabled
sortStatus={sortStatus}
onSortStatusChange={setSortStatus}
noRecordsText={t("errors.noItems")}
idAccessor={(record) => record.uniqueKey}
height="100%"
className="my-table"
defaultColumnProps={{
noWrap: true,
draggable: true,
resizable: true,
cellsStyle: () => ({ padding: `${size.cellPadding}px 8px` }),
}}
scrollAreaProps={{ type: "auto", scrollbarSize: 6 }}
rowBackgroundColor={(record) => conditionalBgMap[record.state]}
onRowContextMenu={handleContextMenu}
rowExpansion={{ ... }}
onScroll={() => { if (contextMenu) closeContextMenu(); }}
/>
```
## 13. Layout Stability
- Don't use `table-layout: fixed` — it fights mantine-datatable's resize logic
- Give non-name columns explicit `width` values so only the name column flexes
- Use `ellipsis: true` on the name column — it handles `text-overflow: ellipsis` internally
- Names should truncate at the cell boundary, not a character count, so the layout is stable regardless of content length
- `flexShrink: 0` on badges/icons prevents them from being squeezed by long names
## 14. Checklist for Each Migration
1. Replace imports (`mantine-react-table` → `mantine-datatable`)
2. Convert column definitions (`accessorKey` → `accessor`, `header` → `title`, `Cell` → `render`, etc.)
3. Implement manual sorting with `useState` + `useMemo`
4. Add CSS file for transparent backgrounds (if widget context)
5. Add responsive column visibility (if widget context)
6. Add hidden options + hydration logic (if column persistence needed)
7. Add translation keys (including hidden option labels)
8. Add context menu if row actions exist
9. Add row expansion if detail view exists
10. Add error handling on all mutations
11. Add accessibility attributes
12. Test at multiple widget widths
13. Update docs in `apps/docs/docs/widgets/` if applicable
14. Run `pnpm turbo typecheck`
15. Run translation spec — catches missing keys
@@ -0,0 +1,44 @@
---
name: documentation-sync
description: Keep Homarr documentation in sync with code changes. Use when modifying code that affects user-facing behavior, or when adding/modifying widgets, integrations, cron jobs, API routes, env vars, permissions, auth providers, or UI in apps/docs. Covers the docs/ mapping table, integration doc pattern, and widget doc pattern.
---
# Documentation Sync
When modifying code that affects user-facing behavior, you MUST also update the documentation in `apps/docs/`.
## What triggers a doc update
| Code change | Doc location |
| ---------------------- | ----------------------------------------------------------- |
| New integration | `apps/docs/docs/integrations/<slug>/index.mdx` + `index.ts` |
| New widget | `apps/docs/docs/widgets/<slug>/index.mdx` + `index.ts` |
| Changed API surface | `apps/docs/docs/management/api.mdx` |
| New/changed env vars | `apps/docs/docs/advanced/` |
| New CLI commands | `apps/docs/docs/advanced/command-line/` |
| Changed auth providers | `apps/docs/docs/advanced/` SSO pages |
| UI/UX changes | Relevant getting-started or management pages |
| New cron job | `apps/docs/docs/management/tasks.mdx` |
| Changed permissions | `apps/docs/docs/management/users.mdx` |
## Integration doc pattern
Each integration has a folder under `apps/docs/docs/integrations/<slug>/`:
- `index.ts` — exports a typed `IntegrationDefinition` with name, description, iconUrl, path
- `index.mdx` — uses shared components: `IntegrationHeader`, `IntegrationCapabilites`, `IntegrationSecrets`
- Import metadata from `@homarr/definitions` where possible
## Widget doc pattern
Each widget has a folder under `apps/docs/docs/widgets/<slug>/`:
- `index.ts` — exports a typed `WidgetDefinition` with icon, name, description, path, configuration
- `index.mdx` — uses shared components: `WidgetHeader`, `WidgetConfig`, `WidgetAdding`
## Development
- Run docs locally: `pnpm dev:docs` from root
- Build docs: `pnpm turbo build --filter=@homarr/docs`
- The docs app can import from `@homarr/definitions` for type-safe integration/widget metadata
- Docusaurus strict mode throws on broken links — fix any broken references before committing
@@ -1,13 +1,14 @@
---
description: How to expose tRPC procedures as MCP tools for AI clients
globs: packages/api/src/router/**/*.ts
alwaysApply: false
name: mcp-integration
description: Expose tRPC procedures as MCP tools for AI clients. Use when modifying procedures in packages/api/src/router, adding a new tRPC procedure or router, or deciding what to expose via Homarr's MCP interface. Covers .meta({ mcp }), router registration in packages/api/src/mcp.ts, input schema rules, and what to expose vs skip.
---
# MCP Integration Guide
# MCP Integration
Every new tRPC procedure that provides useful functionality should be exposed as an MCP tool so AI assistants (Claude, Cursor, etc.) can use it. This is a first-class feature of Homarr.
Exposing a procedure makes it callable by any AI client with an API key. Before adding `.meta({ mcp })`, review what the tool exposes: authorization requirements, sensitive data, tenant isolation, auditability, and whether the action is destructive. Prefer exposing read-only queries over mutations unless the mutation is safe and permission-scoped. When in doubt, ask for a security review before shipping a new MCP tool.
## Adding MCP to a procedure
Add `.meta({ mcp: { enabled: true, description: "..." } })` to the procedure chain:
@@ -16,7 +17,7 @@ Add `.meta({ mcp: { enabled: true, description: "..." } })` to the procedure cha
// Read-only tool (query)
myProcedure: protectedProcedure
.meta({ mcp: { enabled: true, description: "Get all items with their status and metadata" } })
.input(z.object({ limit: z.number().default(50) }))
.input(z.object({ limit: z.number().default(10) }))
.query(async ({ ctx, input }) => { ... })
// Write tool (mutation)
@@ -38,23 +39,27 @@ The `.meta()` call must come **before** `.input()` and `.query()`/`.mutation()`
The description is the **only thing** an AI sees to decide when and how to use the tool. Write it like you're explaining to a colleague who has never used Homarr.
**Must include:**
- What the tool returns or does
- Which integrations/services it works with (if applicable)
- How to get required IDs (e.g., "Use integration_all to get the integrationId")
- Permission requirements (if non-obvious)
**Good:**
```
```text
"Get calendar events for upcoming and recent media releases. Fetches from all connected Sonarr (TV), Radarr (movies), Lidarr (music), and Readarr (books) integrations. Requires integrationIds from integration_all"
```
**Bad:**
```
```text
"Get calendar events"
```
**For tools that return permission fields**, explain what they mean:
```
```text
"List all integrations. Returns permissions.hasUseAccess (read) and permissions.hasInteractAccess (actions) — false means the API key lacks that permission, not an error"
```
@@ -77,11 +82,13 @@ export const mcpRouter = createTRPCRouter({
## What to expose vs. what to skip
**Expose:**
- Data queries (list, search, get by ID)
- Actions users would ask an AI to do (toggle, create, delete, approve)
- Status checks (health, stats, summaries)
**Skip:**
- Subscriptions (WebSocket-only, not supported by MCP)
- Internal procedures (session management, onboarding steps)
- File upload/download procedures
+1
View File
@@ -0,0 +1 @@
../.agents/skills
-50
View File
@@ -1,50 +0,0 @@
---
description: Keep documentation in sync with code changes
globs:
- packages/definitions/src/**
- packages/widgets/src/**
- packages/integrations/src/**
- packages/api/src/**
- apps/nextjs/src/**
- apps/docs/**
---
# Documentation Sync Rule
When modifying code that affects user-facing behavior, you MUST also update the documentation in `apps/docs/`.
## What triggers a doc update
| Code change | Doc location |
|---|---|
| New integration | `apps/docs/docs/integrations/<slug>/index.mdx` + `index.ts` |
| New widget | `apps/docs/docs/widgets/<slug>/index.mdx` + `index.ts` |
| Changed API surface | `apps/docs/docs/management/api.mdx` |
| New/changed env vars | `apps/docs/docs/advanced/` |
| New CLI commands | `apps/docs/docs/advanced/command-line/` |
| Changed auth providers | `apps/docs/docs/advanced/` SSO pages |
| UI/UX changes | Relevant getting-started or management pages |
| New cron job | `apps/docs/docs/management/tasks.mdx` |
| Changed permissions | `apps/docs/docs/management/users.mdx` |
## Integration doc pattern
Each integration has a folder under `apps/docs/docs/integrations/<slug>/`:
- `index.ts` — exports a typed `IntegrationDefinition` with name, description, iconUrl, path
- `index.mdx` — uses shared components: `IntegrationHeader`, `IntegrationCapabilites`, `IntegrationSecrets`
- Import metadata from `@homarr/definitions` where possible
## Widget doc pattern
Each widget has a folder under `apps/docs/docs/widgets/<slug>/`:
- `index.ts` — exports a typed `WidgetDefinition` with icon, name, description, path, configuration
- `index.mdx` — uses shared components: `WidgetHeader`, `WidgetConfig`, `WidgetAdding`
## Development
- Run docs locally: `pnpm dev:docs` from root
- Build docs: `pnpm turbo build --filter=@homarr/docs`
- The docs app can import from `@homarr/definitions` for type-safe integration/widget metadata
- Docusaurus strict mode throws on broken links — fix any broken references before committing
+9 -1
View File
@@ -6,11 +6,19 @@ npm-debug.log
README.md
.next
.turbo
.pnpm-store
**/.pnpm-store
coverage
**/coverage
**/.docusaurus
**/build
.git
.github
dev
.build
e2e
apps/docs
apps/docs/*
!apps/docs/package.json
apps/nextjs/.next
.env
.env.*
+8 -1
View File
@@ -59,4 +59,11 @@ TURBO_TELEMETRY_DISABLED=1
# ENABLE_KUBERNETES=true
# Enable mock integration
UNSAFE_ENABLE_MOCK_INTEGRATION=true
UNSAFE_ENABLE_MOCK_INTEGRATION=true
# Enable demo mode (seeds a demo user "demo"/"demo", a sample board and a mock integration)
# DEMO_MODE=true
# Whether demo mode is read-only. Defaults to true (the public demo blocks all mutations).
# Set to false for writable preview deployments so the demo user can modify the dashboard.
# DEMO_READ_ONLY=false
+14
View File
@@ -33,6 +33,20 @@ body:
options:
# The below comment is used to insert a new version with on-release.yml
#NEXT_VERSION#
- 1.77.0
- 1.76.2
- 1.76.1
- 1.76.0
- 1.75.0
- 1.74.0
- 1.73.0
- 1.72.0
- 1.71.0
- 1.70.0
- 1.69.2
- 1.69.0
- 1.68.0
- 1.67.0
- 1.66.1
- 1.66.0
- 1.65.0
+2
View File
@@ -0,0 +1,2 @@
.secrets
!.secrets.example
+4
View File
@@ -0,0 +1,4 @@
TURBO_API=
TURBO_TEAM=
TURBO_TOKEN=
TURBO_REMOTE_CACHE_SIGNATURE_KEY=
+36
View File
@@ -0,0 +1,36 @@
# Running CI locally
Install [Act](https://nektosact.com/installation/index.html) and ensure Docker is running, then use:
```bash
pnpm ci:act:fast
pnpm ci:act:docker
pnpm ci:act:all
pnpm ci:act:cleanup
```
`fast` runs the quality gate. `docker` and `all` run the gate followed by the single container build, E2E suite, and memory regression test. `cleanup` validates the manual cleanup path without calling GitHub. The wrapper supports regular clones and Git worktrees, including non-default Docker contexts. Linux dependencies are kept in Docker volumes instead of overwriting host `node_modules`. The first run downloads the Act runner and Playwright browser dependencies.
Remote caching is optional locally. Copy `.github/act/.secrets.example` to `.github/act/.secrets`, populate it with rotated credentials, and run with:
```bash
ACT_SECRET_FILE=.github/act/.secrets pnpm ci:act:all
```
Act never publishes or deletes GHCR images. The secret file is ignored by Git.
## PR preview images
Successful non-draft pull requests from this repository publish an amd64 image:
```bash
docker pull ghcr.io/homarr-labs/homarr-test:pr-<number>
```
The tag is replaced when the pull request is updated and deleted when it closes. Production Homarr images remain the supported multi-architecture releases. The `homarr-test` package must be configured as public in GHCR for unauthenticated testers.
## Dokploy preview cache
Keep `needs-demo` as the Dokploy preview label. Under the application's **Preview Build-time Secrets**, configure `TURBO_API`, `TURBO_TEAM`, `TURBO_TOKEN`, and `TURBO_REMOTE_CACHE_SIGNATURE_KEY`. Dokploy passes these to the Dockerfile as BuildKit secrets. Do not configure the token or signature key as Docker build arguments.
Rotate any credentials that have appeared in chat, logs, or committed configuration before enabling the cache.
+1 -1
View File
@@ -11,7 +11,7 @@ outputs:
runs:
using: "composite"
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up Docker Buildx
+8
View File
@@ -11,3 +11,11 @@
- [ ] Commits follow the [conventional commits guideline](https://www.conventionalcommits.org/en/v1.0.0/)
- [ ] No shorthand variable names are used (eg. `x`, `y`, `i` or any abbrevation)
- [ ] Documentation is up to date. Create a pull request [here](https://github.com/homarr-labs/documentation/).
- [ ] When using AI; No temp files are checked in, the code style follows the rest of the project
**When contributing a new integration or widget:**
- [ ] I confirmed manually that the integration or widget is working with a real system and performed basic smoke
tests (e.g. what happens if it is offline)
- [ ] Optional but recommended: I confirm that I am willing to be added to the `CODEOWNERS` of this feature and will
provide support and maintain the integration (e.g. in case of breaking or failure)
+2 -2
View File
@@ -1,6 +1,6 @@
{
$schema: "https://docs.renovatebot.com/renovate-schema.json",
extends: ["config:recommended"],
extends: ["config:recommended", ":dependencyDashboardApproval"],
packageRules: [
{
matchPackageNames: ["^@homarr/"],
@@ -47,7 +47,7 @@
rangeStrategy: "bump",
automerge: false,
baseBranchPatterns: ["dev"],
dependencyDashboard: false,
dependencyDashboard: true,
// prevent special characters in branch names (otherwise git errors occur on windows)
branchNameStrict: true,
}
+47
View File
@@ -0,0 +1,47 @@
name: Auto-fix lint and format
on:
pull_request:
types: [opened, synchronize, reopened]
branches: ["*"]
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
autofix:
name: Auto-fix
if: github.event.pull_request.head.repo.id == github.repository_id
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
ref: ${{ github.head_ref }}
- name: Setup
uses: ./tooling/github/setup
- name: Get changed files
id: changed
env:
BASE_REF: ${{ github.base_ref }}
run: |
git diff --name-only --diff-filter=ACMR "origin/${BASE_REF}...HEAD" -- '*.ts' '*.tsx' '*.js' '*.jsx' > /tmp/changed-files
echo "count=$(wc -l < /tmp/changed-files | tr -d '[:space:]')" >> $GITHUB_OUTPUT
- name: Auto-fix lint + format
if: steps.changed.outputs.count != '0'
run: |
xargs -r -a /tmp/changed-files pnpm exec oxlint --fix || true
xargs -r -a /tmp/changed-files pnpm exec oxfmt --write
- name: Commit fixes
uses: stefanzweifel/git-auto-commit-action@v7
with:
commit_message: "style: auto-fix lint and format"
-35
View File
@@ -1,35 +0,0 @@
name: "[Dependency Updates] Auto Approve"
on:
pull_request:
types: [opened, synchronize]
permissions: {}
jobs:
approve-automatic-prs:
runs-on: ubuntu-latest
timeout-minutes: 2
# 158783068: homarr-renovate[bot]
# 190541745: homarr-crowdin[bot]
# 210161987: homarr-update-contributors[bot]
# 175486441: homarr-releases[bot]
# Extracted from https://api.github.com/users/<username>
if: github.actor_id == 158783068 || github.actor_id == 190541745 || github.actor_id == 210161987 || github.actor_id == 175486441
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Obtain token
id: obtainToken
uses: actions/create-github-app-token@v3
with:
private-key: ${{ secrets.RENOVATE_APPROVE_PRIVATE_KEY }}
client-id: ${{ secrets.RENOVATE_APPROVE_APP_ID }}
permission-pull-requests: write # required to approve pull request
- name: Install GitHub CLI
run: sudo apt-get install -y gh
- name: Approve automatic PRs
env:
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
run: |
gh pr review ${{github.event.pull_request.number}} --approve --body "Automatically approved by GitHub Action"
@@ -0,0 +1,43 @@
name: "[Bots] Reconcile Auto-merge"
on:
schedule:
- cron: "*/30 * * * *"
workflow_dispatch:
permissions: {}
jobs:
reconcile:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Obtain token
id: obtainToken
uses: actions/create-github-app-token@v3
with:
private-key: ${{ secrets.RENOVATE_APPROVE_PRIVATE_KEY }}
client-id: ${{ secrets.RENOVATE_APPROVE_APP_ID }}
permission-pull-requests: write # required to enable auto-merge
- name: Install GitHub CLI
run: sudo apt-get install -y gh
- name: Re-enable auto-merge for prepared bot PRs
env:
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
run: |
# 158783068: homarr-renovate[bot]
# 190541745: homarr-crowdin[bot]
# 210161987: homarr-update-contributors[bot]
# 175441: homarr-releases[bot]
gh pr list --repo "${{ github.repository }}" --base dev --state open --limit 100 \
--json number,author,reviewDecision,mergeStateStatus,autoMergeRequest \
--jq '.[] | select(.author.login as $login | ["app/homarr-renovate", "app/homarr-crowdin", "app/homarr-update-contributors", "app/homarr-releases"] | index($login)) | select(.reviewDecision == "APPROVED") | select(.mergeStateStatus == "CLEAN") | select(.autoMergeRequest == null) | .number' \
| while read -r pr; do
echo "Re-enabling auto-merge on PR #$pr"
gh pr merge "$pr" --auto --squash
done
+47
View File
@@ -0,0 +1,47 @@
name: "[Bots] Approve and Auto-merge"
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions: {}
jobs:
approve-and-automerge:
runs-on: ubuntu-latest
timeout-minutes: 5
# 158783068: homarr-renovate[bot]
# 190541745: homarr-crowdin[bot]
# 210161987: homarr-update-contributors[bot]
# 175441: homarr-releases[bot]
# Extracted from https://api.github.com/users/<username>
if: |
(github.actor_id == 158783068 || github.actor_id == 190541745 || github.actor_id == 210161987 || github.actor_id == 175441) &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.event.pull_request.base.ref == 'dev'
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Obtain token
id: obtainToken
uses: actions/create-github-app-token@v3
with:
private-key: ${{ secrets.RENOVATE_APPROVE_PRIVATE_KEY }}
client-id: ${{ secrets.RENOVATE_APPROVE_APP_ID }}
permission-pull-requests: write # required to approve a pull request and enable auto-merge
- name: Install GitHub CLI
run: sudo apt-get install -y gh
- name: Approve and enable auto-merge
env:
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
run: |
PR_NUMBER="${{ github.event.pull_request.number }}"
if [ "$(gh pr view "$PR_NUMBER" --json reviewDecision --jq .reviewDecision)" != "APPROVED" ]; then
gh pr review "$PR_NUMBER" --approve --body "Automatically approved by Homarr bot policy"
fi
if [ "$(gh pr view "$PR_NUMBER" --json autoMergeRequest --jq '.autoMergeRequest != null')" != "true" ]; then
gh pr merge "$PR_NUMBER" --auto --squash
fi
+264
View File
@@ -0,0 +1,264 @@
name: CI
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches: ["*"]
pull_request_target:
types: [closed]
branches: ["*"]
push:
branches: [main, dev, beta, next]
merge_group:
workflow_dispatch:
inputs:
operation:
description: Operation to run
required: true
default: validate
type: choice
options:
- validate
- publish
- cleanup
pr_number:
description: PR number for publish or cleanup
required: false
type: number
ref:
description: Git ref to validate or publish
required: false
type: string
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || inputs.pr_number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
env:
FORCE_COLOR: 3
SKIP_ENV_VALIDATION: true
TURBO_TELEMETRY_DISABLED: 1
REGISTRY: ghcr.io
PREVIEW_IMAGE: ghcr.io/homarr-labs/homarr-test
jobs:
fast-gate:
name: Fast gate
if: github.event_name != 'pull_request_target' && (github.event_name != 'workflow_dispatch' || inputs.operation != 'cleanup')
runs-on: ubuntu-latest
timeout-minutes: 15
env:
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 }}
TURBO_SCM_BASE: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before || 'HEAD~1' }}
TURBO_SCM_HEAD: ${{ github.sha }}
TURBO_PLATFORM: linux/amd64
steps:
- uses: actions/checkout@v7
if: "!env.ACT"
with:
fetch-depth: 0
persist-credentials: false
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || '' }}
- name: Validate manual inputs
if: github.event_name == 'workflow_dispatch' && inputs.operation == 'publish'
env:
PR_NUMBER: ${{ inputs.pr_number }}
BUILD_REF: ${{ inputs.ref }}
run: |
test -n "$PR_NUMBER" || { echo "pr_number is required for publish"; exit 1; }
test -n "$BUILD_REF" || { echo "ref is required for publish"; exit 1; }
- name: Setup
uses: ./tooling/github/setup
- name: Copy environment defaults
run: cp .env.example .env
- name: Lint, typecheck, and build affected workspaces
run: pnpm turbo run lint typecheck build --affected --continue=dependencies-successful --concurrency=2
- name: Validate workspace configuration
run: pnpm lint:ws
- name: Run unit tests
run: pnpm test
container:
name: Container and E2E
needs: fast-gate
if: |
github.event_name == 'merge_group' ||
(github.event_name == 'pull_request' && github.event.pull_request.draft == false) ||
(github.event_name == 'workflow_dispatch' && (inputs.operation == 'validate' || inputs.operation == 'publish'))
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v7
if: "!env.ACT"
with:
persist-credentials: false
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || '' }}
- name: Setup
uses: ./tooling/github/setup
- name: Set up Docker Buildx
if: "!env.ACT"
uses: docker/setup-buildx-action@v4
- name: Build container once
if: "!env.ACT"
uses: docker/build-push-action@v7
with:
context: .
network: host
platforms: linux/amd64
load: true
push: false
tags: |
homarr-ci
homarr-e2e
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.ref.name=pr-${{ github.event.pull_request.number || inputs.pr_number || 'none' }}
cache-from: type=gha,scope=homarr-linux-amd64
cache-to: type=gha,scope=homarr-linux-amd64,mode=max
secrets: |
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 }}
- name: Build container once with Act
if: env.ACT
env:
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 }}
run: |
secret_args=()
for secret in TURBO_API TURBO_TEAM TURBO_TOKEN TURBO_REMOTE_CACHE_SIGNATURE_KEY; do
if [ -n "${!secret:-}" ]; then
secret_args+=(--secret "id=${secret},env=${secret}")
fi
done
DOCKER_BUILDKIT=1 docker build --platform linux/amd64 \
--tag homarr-ci --tag homarr-e2e "${secret_args[@]}" .
- name: Cache Playwright browsers
if: "!env.ACT"
id: playwright-cache
uses: actions/cache@v6
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install Playwright Chromium
if: steps.playwright-cache.outputs.cache-hit != 'true' || env.ACT
run: pnpm exec playwright install --with-deps chromium
- name: Install Playwright system deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: pnpm exec playwright install-deps chromium
- name: Run E2E tests
run: pnpm test:e2e
- name: Upload E2E artifacts
if: failure() && !env.ACT
uses: actions/upload-artifact@v7
with:
name: playwright-report
path: e2e/test-results/
retention-days: 7
- name: Determine preview tag
id: preview
if: |
!env.ACT &&
(
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) ||
(github.event_name == 'workflow_dispatch' && inputs.operation == 'publish')
)
env:
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }}
run: echo "tag=pr-${PR_NUMBER}" >> "$GITHUB_OUTPUT"
- name: Log in to GHCR
if: steps.preview.outputs.tag != ''
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push preview image
if: steps.preview.outputs.tag != ''
env:
PREVIEW_TAG: ${{ steps.preview.outputs.tag }}
run: |
docker tag homarr-ci "${PREVIEW_IMAGE}:${PREVIEW_TAG}"
docker push "${PREVIEW_IMAGE}:${PREVIEW_TAG}"
- name: Show Act publication result
if: env.ACT
run: echo "Act validated the publication path; external GHCR writes are disabled locally."
cleanup:
name: Clean up preview image
if: github.event_name == 'pull_request_target' || (github.event_name == 'workflow_dispatch' && inputs.operation == 'cleanup')
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
packages: write
env:
IMAGE_TAG: pr-${{ github.event.pull_request.number || inputs.pr_number }}
steps:
- name: Validate cleanup input
if: github.event_name == 'workflow_dispatch'
env:
PR_NUMBER: ${{ inputs.pr_number }}
run: test -n "$PR_NUMBER" || { echo "pr_number is required for cleanup"; exit 1; }
- name: Delete GHCR package version
if: "!env.ACT"
uses: actions/github-script@v8
with:
script: |
const packageName = "homarr-test";
const org = context.repo.owner;
const tag = process.env.IMAGE_TAG;
const versions = await github.paginate(
github.rest.packages.getAllPackageVersionsForPackageOwnedByOrg,
{ package_type: "container", package_name: packageName, org, per_page: 100 },
);
const target = versions.find((version) =>
version.metadata?.container?.tags?.includes(tag),
);
if (!target) {
core.info(`No package version found with tag "${tag}"`);
return;
}
await github.rest.packages.deletePackageVersionForOrg({
package_type: "container",
package_name: packageName,
org,
package_version_id: target.id,
});
core.info(`Deleted package version ${target.id} (${tag})`);
- name: Show Act cleanup result
if: env.ACT
run: echo "Act validated cleanup for ${IMAGE_TAG}; external GHCR writes are disabled locally."
-165
View File
@@ -1,165 +0,0 @@
name: "[Quality] Code Analysis"
permissions:
contents: read
on:
pull_request:
branches: ["*"]
push:
branches: ["main"]
merge_group:
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
env:
FORCE_COLOR: 3
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 }}
TURBO_SCM_BASE: ${{ github.event.pull_request.base.sha || github.event.before || 'HEAD~1' }}
TURBO_SCM_HEAD: ${{ github.sha }}
jobs:
lint-format-autofix:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ github.head_ref }}
- name: Setup
uses: ./tooling/github/setup
- name: Get changed files
id: changed
run: |
git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }}...HEAD -- '*.ts' '*.tsx' '*.js' '*.jsx' > /tmp/changed-files
echo "count=$(wc -l < /tmp/changed-files | tr -d '[:space:]')" >> $GITHUB_OUTPUT
- name: Auto-fix lint + format
if: steps.changed.outputs.count != '0'
run: |
xargs -r -a /tmp/changed-files pnpm exec oxlint --fix || true
xargs -r -a /tmp/changed-files pnpm exec oxfmt --write
- name: Commit fixes
uses: stefanzweifel/git-auto-commit-action@v7
with:
commit_message: "style: auto-fix lint and format"
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup
uses: ./tooling/github/setup
- name: Copy env
shell: bash
run: cp .env.example .env
- name: Lint
run: pnpm turbo lint --affected && pnpm lint:ws
format:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup
uses: ./tooling/github/setup
- name: Format
run: pnpm turbo format --affected --continue
typecheck:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup
uses: ./tooling/github/setup
- name: Typecheck
run: pnpm turbo typecheck --affected
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- name: Setup
uses: ./tooling/github/setup
- name: Test
run: pnpm test
- name: "Report Coverage"
# Set if: always() to also generate the report if tests are failing
# Only works if you set `reportOnFailure: true` in your vite config as specified above
if: always()
uses: davelosert/vitest-coverage-report-action@v2
e2e:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
- name: Setup
uses: ./tooling/github/setup
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build docker image
id: build-docker-image
uses: docker/build-push-action@v7
with:
platforms: linux/amd64
context: .
push: false
load: true
tags: homarr-e2e
network: host
cache-from: type=gha
cache-to: type=gha,mode=max
env:
SKIP_ENV_VALIDATION: true
- name: Install playwright browsers
run: pnpm exec playwright install chromium
- name: Run E2E Tests
shell: bash
run: pnpm test:e2e
build:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup
uses: ./tooling/github/setup
- name: Copy env
shell: bash
run: cp .env.example .env
- name: Build
run: pnpm turbo build --affected
@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Obtain token
id: obtainToken
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Upload Crowdin translations
uses: crowdin/github-action@v2
@@ -26,7 +26,7 @@ jobs:
with:
args: "Beta release has been triggered: [run ${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Get Next Version
+14 -6
View File
@@ -57,7 +57,7 @@ jobs:
client-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
permission-contents: write # required to commit package.json & changelog changes, merge them to dev / next and publish the release
- uses: actions/checkout@v6
- uses: actions/checkout@v7
if: env.SKIP_RELEASE == 'false'
with:
persist-credentials: false
@@ -66,10 +66,8 @@ jobs:
- uses: actions/setup-node@v6
if: env.SKIP_RELEASE == 'false'
with:
node-version: 24.16.0
node-version: 24.18.0
package-manager-cache: false
- run: npm i -g pnpm
if: env.SKIP_RELEASE == 'false'
- name: Install dependencies
if: env.SKIP_RELEASE == 'false'
run: |
@@ -119,7 +117,7 @@ jobs:
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
ref: ${{ needs.release.outputs.git_ref }}
@@ -148,6 +146,11 @@ jobs:
platforms: linux/amd64
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
secrets: |
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 }}
env:
SKIP_ENV_VALIDATION: true
build-arm64:
@@ -158,7 +161,7 @@ jobs:
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
ref: ${{ needs.release.outputs.git_ref }}
@@ -187,6 +190,11 @@ jobs:
platforms: linux/arm64
labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,"name=${{ env.GHCR_REPO }}",push-by-digest=true,name-canonical=true,push=true
secrets: |
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 }}
env:
SKIP_ENV_VALIDATION: true
extract-asset-amd64:
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Setup
uses: ./tooling/github/setup
- name: Build docs
@@ -3,6 +3,7 @@ name: "[Deployment] Automatic Weekly Release"
on:
schedule:
- cron: "0 19 * * 5" # https://crontab.guru/#0_19_*_*_5
timezone: Europe/Zurich
workflow_dispatch:
inputs:
send-notifications:
@@ -28,7 +29,7 @@ jobs:
with:
args: "Automatic release has been triggered: [run ${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Get Next Version
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Setup
uses: ./tooling/github/setup
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
ref: dev
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
ref: dev
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Validate prebuilt dependencies for amd64
id: validate-amd64
uses: ./.github/actions/prebuilt-debian
@@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Validate prebuilt dependencies for arm64
id: validate-arm64
uses: ./.github/actions/prebuilt-debian
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- run: |
npx --yes --package renovate -- \
renovate-config-validator --strict .github/renovate.json5
+1 -1
View File
@@ -52,7 +52,7 @@ jobs:
permission-contents: write # required to commit to branch
permission-pull-requests: write # required to create pr & enable automerge
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
token: ${{ steps.obtainToken.outputs.token }}
ref: dev
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
permission-pull-requests: write # required to create pr & enable automerge
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
env:
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
@@ -28,7 +28,7 @@ jobs:
permission-contents: write # required to commit to branch
permission-pull-requests: write # required to create pr & enable automerge
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v7
env:
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
- name: Setup
+6
View File
@@ -2,6 +2,7 @@
# dependencies
node_modules
.pnpm-store/
.pnp
.pnp.js
.idea/
@@ -70,7 +71,12 @@ apps/nextjs/public/images/background.png
# personal agent config
.opencode
.agents/*
!.agents/skills/
skills-lock.json
# docusaurus
apps/docs/.docusaurus
apps/docs/build
.pnpm-store
benchmark-results
+8
View File
@@ -0,0 +1,8 @@
{
"mcpServers": {
"mantine": {
"command": "npx",
"args": ["-y", "@mantine/mcp-server"]
}
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
[tools]
node = "24.16.0"
node = "24.18.0"
+1 -1
View File
@@ -1 +1 @@
24.16.0
24.18.0
+1 -1
View File
@@ -1,7 +1,7 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"oxc.oxc-vscode",
"yoavbls.pretty-ts-errors",
"million.million-lint",
"lokalise.i18n-ally"
+19
View File
@@ -46,6 +46,8 @@ homarr/
├── tooling/
│ ├── typescript/ # Base tsconfig
│ └── github/ # CI setup action
├── tools/
│ └── homarr-dev/ # Go CLI for local and PR Docker images
├── development/ # Dev docker-compose (Redis, MySQL, PostgreSQL)
├── e2e/ # E2E test specs
└── Dockerfile # Multi-stage production build
@@ -68,6 +70,9 @@ When modifying user-facing code, you MUST also update the corresponding document
## Monorepo Commands
- `pnpm dev` — Next.js app only
- `pnpm dev:cli -- dev` — run the developer CLI without installing a global binary
- `pnpm db:seed` — seed default database data explicitly
- `pnpm docker:dev:up` — start the Redis development service in the background
- `pnpm dev:docs` — Docusaurus docs site only
- `pnpm turbo build` — build all packages
- `pnpm turbo build --filter=@homarr/docs` — build docs only
@@ -79,5 +84,19 @@ When modifying user-facing code, you MUST also update the corresponding document
- Lint: oxlint (not ESLint)
- Format: oxfmt (not Prettier)
- UI: Mantine (not Tailwind) — Tailwind is only used in docs app
- Mantine: use the `mantine` MCP server (configured in `.mcp.json`; tools `get_item_doc` / `get_item_props` / `search_docs`) for current v9 APIs before writing component code. Prefer built-in primitives (`Combobox`/`useCombobox` for selects, the polymorphic `component` prop, `@mantine/hooks`) over hand-rolled equivalents. Check `packages/ui/` for existing conventions first.
## MCP servers
`.mcp.json` at the repo root declares project-scoped MCP servers (the standard Claude Code layout; other tools can import the same `mcpServers` block). See the `mantine` entry there for the Mantine v9 server, and the upstream docs at https://mantine.dev/guides/llms/ for per-tool setup (OpenCode: `.opencode/opencode.json`, Codex: `.codex/config.toml`). Only keyless server definitions belong in `.mcp.json`; anything needing secrets stays in local dotfiles.
## Agent Skills
Portable agent skills live in `.agents/skills/` (the Agent Skills open standard). Cursor, Codex, and OpenCode read `.agents/skills/` natively. Claude Code does not scan it, so `.claude/skills/` is a symlink back to `.agents/skills/`. Install skills at `.agents/skills/<name>/SKILL.md` — that single copy is used everywhere. See `.agents/skills/` for available skills (documentation-sync, mcp-integration, codebase-context, datatable-migration).
- Icons: @tabler/icons-react
- Docs app can import from `@homarr/definitions` for shared types
- Run `pnpm dev:cli -- dev` to browse local `homarr:*` images and remote PR images.
- Run `pnpm dev:cli -- build <name>` from a Homarr checkout to build `homarr:<name>` with rebuild provenance.
- Run `pnpm dev:cli -- build --pr <number>` to build a PR locally from a temporary checkout.
- Run Go checks from `tools/homarr-dev` with `go test ./...` and `go vet ./...`.
+113
View File
@@ -1,3 +1,116 @@
## [1.77.1](https://github.com/homarr-labs/homarr/compare/v1.77.0...v1.77.1) (2026-09-11)
## [1.77.0](https://github.com/homarr-labs/homarr/compare/v1.76.2...v1.77.0) (2026-09-06)
## [1.76.2](https://github.com/homarr-labs/homarr/compare/v1.76.1...v1.76.2) (2026-08-27)
## [1.76.1](https://github.com/homarr-labs/homarr/compare/v1.76.0...v1.76.1) (2026-08-26)
## [1.76.0](https://github.com/homarr-labs/homarr/compare/v1.75.0...v1.76.0) (2026-08-21)
## [1.75.0](https://github.com/homarr-labs/homarr/compare/v1.74.0...v1.75.0) (2026-08-14)
## [1.74.0](https://github.com/homarr-labs/homarr/compare/v1.73.0...v1.74.0) (2026-08-07)
## [1.73.0](https://github.com/homarr-labs/homarr/compare/v1.72.0...v1.73.0) (2026-07-31)
## [1.72.0](https://github.com/homarr-labs/homarr/compare/v1.71.0...v1.72.0) (2026-07-24)
## [1.71.0](https://github.com/homarr-labs/homarr/compare/v1.70.0...v1.71.0) (2026-07-17)
## [1.70.0](https://github.com/homarr-labs/homarr/compare/v1.69.2...v1.70.0) (2026-07-10)
## [1.69.2](https://github.com/homarr-labs/homarr/compare/v1.69.1...v1.69.2) (2026-07-06)
### Bug Fixes
* **layout:** raise AppShellHeader z-index above Indicator dots ([687edb9](https://github.com/homarr-labs/homarr/commit/687edb9226307cb83986097abb24fe7f672e1778)), closes [#6194](https://github.com/homarr-labs/homarr/issues/6194)
## [1.69.1](https://github.com/homarr-labs/homarr/compare/v1.69.0...v1.69.1) (2026-07-04)
### Bug Fixes
* unblock query cache mutations in demo mode and add cache buster ([#6176](https://github.com/homarr-labs/homarr/issues/6176)) ([a382c75](https://github.com/homarr-labs/homarr/commit/a382c75968e73bafff55b5890b1e95f0779b50d3))
## [1.69.0](https://github.com/homarr-labs/homarr/compare/v1.68.1...v1.69.0) (2026-07-03)
### Features
* add per-widget secret storage for release provider authentication ([77884a3](https://github.com/homarr-labs/homarr/commit/77884a31794e12a6f7bc59d96c8f61aa429ca68d))
* **config:** enable pnpm global virtual store for worktree support ([#6098](https://github.com/homarr-labs/homarr/issues/6098)) ([3864727](https://github.com/homarr-labs/homarr/commit/3864727502a64052c4e3838468094b30bf04a133))
* **docker-widget:** add per-column visibility toggle ([#6093](https://github.com/homarr-labs/homarr/issues/6093)) ([0765262](https://github.com/homarr-labs/homarr/commit/076526293d13379004461633d7ba4c2e83bd5ffe))
* **docs:** addd in documentation for archiveteam warrior ([f66469d](https://github.com/homarr-labs/homarr/commit/f66469d79797a2da214588f4e8253b03633c59a5))
* simplify caching — TanStack Query as single source of truth ([#6075](https://github.com/homarr-labs/homarr/issues/6075)) ([f19033e](https://github.com/homarr-labs/homarr/commit/f19033e0d53d248aed678737f3d04d5d8c7815b5))
* **widgets:** right-click context menu with auto-generated toggle actions ([#6126](https://github.com/homarr-labs/homarr/issues/6126)) ([7e58858](https://github.com/homarr-labs/homarr/commit/7e58858353ae866efd657270d4bb16d2c7d3e551))
* **widgets:** show calendar events on hover with pin on click ([#2637](https://github.com/homarr-labs/homarr/issues/2637)) ([#6081](https://github.com/homarr-labs/homarr/issues/6081)) ([db3d588](https://github.com/homarr-labs/homarr/commit/db3d58821e4de8d46b110125d0fa36919765248f))
### Bug Fixes
* add id to repository schema and handle missing ids gracefully ([8747d5f](https://github.com/homarr-labs/homarr/commit/8747d5f93ee9a295aad3c7035e8c6c7080bf5ee6))
* address PR review - atomic upsert, MCP metadata, stale tokens, save UX ([757d598](https://github.com/homarr-labs/homarr/commit/757d59854e5ec82d91c053b8bc3d7eaf2e70efc4))
* address PR review findings for widget-only integration refactor ([c892731](https://github.com/homarr-labs/homarr/commit/c892731479b47fab6218bd1f52fa6eccbdaa371e))
* address review - paginate GH releases, GitLab tag_name, docs, test ([e687bc8](https://github.com/homarr-labs/homarr/commit/e687bc8c9277797acaa164a09c74b3808a2cb346))
* apply version filter to LinuxServer.io provider ([34d976e](https://github.com/homarr-labs/homarr/commit/34d976eeea09e396334ce8fce5c492c07e7dd32b))
* catch individual repo fetch failures to prevent batch crashes ([d893515](https://github.com/homarr-labs/homarr/commit/d893515b932608ea08c9c6e90b83f340e40f6f8e))
* compile versionRegex once and add fetch timeouts ([64c7512](https://github.com/homarr-labs/homarr/commit/64c75122833981a49e9c8bf1789d501faff6d62d))
* **deps:** update dependency postcss to ^8.5.16 ([#6169](https://github.com/homarr-labs/homarr/issues/6169)) ([9252fdc](https://github.com/homarr-labs/homarr/commit/9252fdc13971bd982224a31d7be577112f99ec45))
* dns-hole widgets showing stale disconnected state ([#6096](https://github.com/homarr-labs/homarr/issues/6096)) ([2443f1c](https://github.com/homarr-labs/homarr/commit/2443f1cd3ff6765a91783d60d42aa03d9ba63fcd))
* gracefully degrade when widget_secret table is missing or access denied ([30107e4](https://github.com/homarr-labs/homarr/commit/30107e4e76a454ff7402de9a8bc2e0dd6f422aa8))
* handle missing widgetSecrets table and add default releases repo ([af35a50](https://github.com/homarr-labs/homarr/commit/af35a50fa05fee2f0118e98727eb108b0200f762))
* **immich:** v3 API compatibility — use searchAssets for album assets, drop deviceAssetId ([#5977](https://github.com/homarr-labs/homarr/issues/5977)) ([a5ec880](https://github.com/homarr-labs/homarr/commit/a5ec880eec276e0814d2ab3ed7f9bc0b804d0465))
* quick wins — calendar, about, glances, admin UX, releases, iframe, notes ([#6116](https://github.com/homarr-labs/homarr/issues/6116)) ([f9da71a](https://github.com/homarr-labs/homarr/commit/f9da71a19bdfa589aafe26b164d0e0782208ac0a))
* restore ArchiveTeam Warrior as a proper integration ([8a5ad58](https://github.com/homarr-labs/homarr/commit/8a5ad5861ba4c2d0978f1fa3f6115a1c5974f8a2))
* **timetable:** restore station search by removing disabled query guard ([d670b69](https://github.com/homarr-labs/homarr/commit/d670b6939672932c1a3d17ab9913901491cb46e3))
* update CHANGES.md for ArchiveTeam Warrior restoration, remove typo translation key ([62baaf7](https://github.com/homarr-labs/homarr/commit/62baaf78130c4b74e899a948cee17097d8c02593))
* verbose error messages in all release providers ([2155f13](https://github.com/homarr-labs/homarr/commit/2155f13f245f601b99458e227b6e058fbfa44cd9))
* **widgets:** make downloads widget table background transparent ([#6025](https://github.com/homarr-labs/homarr/issues/6025)) ([73bed51](https://github.com/homarr-labs/homarr/commit/73bed51df895250f415efd7a87e721e403b3fd99))
## [1.68.1](https://github.com/homarr-labs/homarr/compare/v1.68.0...v1.68.1) (2026-06-30)
### Bug Fixes
* make source maps opt-in to restore v1.67.0 memory baseline ([57ef0af](https://github.com/homarr-labs/homarr/commit/57ef0af4a252ea39727caeba7e13587dabc6254e)), closes [#6123](https://github.com/homarr-labs/homarr/issues/6123)
* revert production source maps to restore v1.67.0 memory baseline ([60a69e3](https://github.com/homarr-labs/homarr/commit/60a69e31efc7168b8f4309daf75954d7730d883b)), closes [#6123](https://github.com/homarr-labs/homarr/issues/6123)
## [1.68.0](https://github.com/homarr-labs/homarr/compare/v1.67.0...v1.68.0) (2026-06-26)
### Features
* add VPN status widget ([#5812](https://github.com/homarr-labs/homarr/issues/5812)) ([a2bb53a](https://github.com/homarr-labs/homarr/commit/a2bb53a8b8fd17da3d2e23851b75d4e179f66225))
* re-add Docker quick-access button in user menu ([#6054](https://github.com/homarr-labs/homarr/issues/6054)) ([abd1635](https://github.com/homarr-labs/homarr/commit/abd16354bc9ef3dddbb497fd16b03476535046ac)), closes [#2165](https://github.com/homarr-labs/homarr/issues/2165)
* ship source maps for readable production stack traces ([#6031](https://github.com/homarr-labs/homarr/issues/6031)) ([89380f8](https://github.com/homarr-labs/homarr/commit/89380f81ddd132f5b1041a8f2c3b6c6b138923dd))
### Bug Fixes
* **beszel:** harden cache layer and prevent blank widgets ([#6052](https://github.com/homarr-labs/homarr/issues/6052)) ([49c2663](https://github.com/homarr-labs/homarr/commit/49c266374df12fea2404710232ced42e2de11dbf)), closes [#6030](https://github.com/homarr-labs/homarr/issues/6030)
* **beszel:** improve stats date display, add click-to-stats modal, fix grid ordering ([#6026](https://github.com/homarr-labs/homarr/issues/6026)) ([55fb227](https://github.com/homarr-labs/homarr/commit/55fb227305fe51963e486ffb25c4ce6811a2f0e4))
* **beszel:** leverage TanStack Query for stale-while-revalidate caching ([#6055](https://github.com/homarr-labs/homarr/issues/6055)) ([bbc4589](https://github.com/homarr-labs/homarr/commit/bbc4589c9e1608721fb58a6f9b03cca8d65c1c4a))
* **beszel:** use 480m interval for 1w/30d stats views ([4383da3](https://github.com/homarr-labs/homarr/commit/4383da38ef634327c288626c58480cc1e5a2f805))
* **beszel:** widget transparency, error handling, and cache invalidation ([#5993](https://github.com/homarr-labs/homarr/issues/5993)) ([39e4245](https://github.com/homarr-labs/homarr/commit/39e424563a3187dcf0dba5f654e2225be76aef51))
* **icon-picker:** keep URL visible in edit mode, add SVG-first ordering ([#6051](https://github.com/homarr-labs/homarr/issues/6051)) ([e01571b](https://github.com/homarr-labs/homarr/commit/e01571b221812cd19a6d67ebe3cf44432104ec27))
* **integrations:** prevent certificate trust button from submitting the form ([#6020](https://github.com/homarr-labs/homarr/issues/6020)) ([0f66bfd](https://github.com/homarr-labs/homarr/commit/0f66bfd6c128253ba644d80d7c908de5314cf997))
* **manage/about:** bypass self-fetch + add manage error boundary (LLM exploration) ([#6009](https://github.com/homarr-labs/homarr/issues/6009)) ([19f9769](https://github.com/homarr-labs/homarr/commit/19f9769d9e669d56d793e9f6a0d265316113d743)), closes [#6008](https://github.com/homarr-labs/homarr/issues/6008) [#6008](https://github.com/homarr-labs/homarr/issues/6008) [#6008](https://github.com/homarr-labs/homarr/issues/6008)
* **plex:** use series title for media releases instead of season label ([#6083](https://github.com/homarr-labs/homarr/issues/6083)) ([2443b89](https://github.com/homarr-labs/homarr/commit/2443b89b46f88fddbf41f0382a9f3bc5469c6fa8))
* show app first in add item modal ([#6087](https://github.com/homarr-labs/homarr/issues/6087)) ([915c8a3](https://github.com/homarr-labs/homarr/commit/915c8a3501551fdccf786d0c34dc01107d873ce0))
* **truenas:** report actual memory usage and pool free space ([#6017](https://github.com/homarr-labs/homarr/issues/6017)) ([f69e545](https://github.com/homarr-labs/homarr/commit/f69e545d6429aece0e55975c3b2426f20e91e545))
* **unraid:** report disk free space instead of total size ([#6018](https://github.com/homarr-labs/homarr/issues/6018)) ([1fb97ee](https://github.com/homarr-labs/homarr/commit/1fb97ee9c6fbe656a7dd3a9d1e436125982533f4))
* **widgets:** clean up health monitoring disk and size display ([#6019](https://github.com/homarr-labs/homarr/issues/6019)) ([e29c79a](https://github.com/homarr-labs/homarr/commit/e29c79a9028d9311dcb3d8323e0950a444589c7a))
* **widgets:** hide health monitoring default tab option for non-proxmox integrations ([#6021](https://github.com/homarr-labs/homarr/issues/6021)) ([52df56b](https://github.com/homarr-labs/homarr/commit/52df56b19da8e0bcb6c2e5df47b7936ec63f3149))
* **widgets:** hide system disk usage value when it overflows and show it in a tooltip ([#6022](https://github.com/homarr-labs/homarr/issues/6022)) ([a19c9d8](https://github.com/homarr-labs/homarr/commit/a19c9d88caacc86b42854c732818f0b5e5cc8dd5))
## [1.67.0](https://github.com/homarr-labs/homarr/compare/v1.66.1...v1.67.0) (2026-06-19)
### Features
* **analytics:** migrate from Umami to PostHog server-side analytics ([#5983](https://github.com/homarr-labs/homarr/issues/5983)) ([d059023](https://github.com/homarr-labs/homarr/commit/d059023b51a323df027c1cf033454440bd0d7e57))
* Calculate and display total CPU and memory usage ([#5911](https://github.com/homarr-labs/homarr/issues/5911)) ([d9cbd54](https://github.com/homarr-labs/homarr/commit/d9cbd5427d0e5be3e5dbecca8d6069dc8074d810))
### Bug Fixes
* **auth:** isolate session cookies from other Auth.js apps on same host ([#5996](https://github.com/homarr-labs/homarr/issues/5996)) ([e1a245f](https://github.com/homarr-labs/homarr/commit/e1a245ff2d8520d08957c4a7dbe01d039607a973))
* **deps:** update tailwindcss monorepo to ^4.3.1 ([#5988](https://github.com/homarr-labs/homarr/issues/5988)) ([78b6e52](https://github.com/homarr-labs/homarr/commit/78b6e520ac095129398d3da8f2441df408e93e9f))
* **downloads:** sort stalled torrents last when sorting by finish time ([#6011](https://github.com/homarr-labs/homarr/issues/6011)) ([c56d9d6](https://github.com/homarr-labs/homarr/commit/c56d9d6894c717b5c70ab75d6a100d4d1071c2d3)), closes [#5416](https://github.com/homarr-labs/homarr/issues/5416)
## [1.65.0](https://github.com/homarr-labs/homarr/compare/v1.64.0...v1.65.0) (2026-06-12)
### Features
+96
View File
@@ -0,0 +1,96 @@
# Changes
## Goal
Remove widget-only services from Homarr's global Integration system.
The affected services are release providers and Search.ch. They are only used by specific widgets, so keeping them as global integrations added unnecessary setup, UI, database rows, docs pages, and integration package code.
ArchiveTeam Warrior remains a proper integration but is no longer auto-seeded on first install.
## Why
These services do not need shared integration state.
- Release providers are selected per Releases widget repository.
- Search.ch is only used by the Timetable widget.
Moving them into widget options makes configuration simpler and removes dead-weight integration code from `packages/integrations`.
## What Changed
### Release Providers
- Added release provider definitions in `packages/definitions/src/release-provider.ts`.
- Removed release providers from `IntegrationKind`.
- Moved release-fetching code out of `packages/integrations` and into `packages/request-handler/src/release-providers.ts`.
- Updated the Releases widget to store provider configuration directly in widget options:
- `provider`
- `identifier`
- `versionFilter`
- `providerUrl`
- Updated the Releases widget editor to use a provider select instead of an integration select.
- Updated Docker import mapping so `ghcr.io` maps to `gitHubContainerRegistry`.
- GitHub Container Registry now uses the public OCI registry API and accepts full image references such as `ghcr.io/homarr-labs/homarr:latest`.
### Timetable / Search.ch
- Removed Search.ch as an integration.
- Added a Timetable widget `baseUrl` option, defaulting to `https://search.ch`.
- Moved Search.ch request/parsing logic into `packages/request-handler/src/timetable.ts`.
- Updated the Timetable API to receive `baseUrl` directly from widget options.
### ArchiveTeam Warrior
- Kept as a proper integration (not removed).
- Removed `defaultUrl` from the integration definition to prevent auto-seeding on first install.
### Integration Cleanup
- Removed creators, exports, docs references, and implementation files for the deleted integrations.
- Removed unused dependencies from `packages/integrations/package.json`.
### Database Migration
- Added `packages/db/migrations/custom/0003_remove_widget_only_integrations.ts`.
- The migration moves old integration-linked widget config into widget options, then deletes the old widget-only integration rows.
- Updated the earlier release widget migration to use the new `provider` field instead of `providerIntegrationId`.
### Docs
- Updated Releases widget docs to describe providers instead of integrations.
- Updated Timetable docs to remove Search.ch integration setup.
- Removed obsolete integration docs pages for the deleted integration kinds.
- Updated docs sitemap and integration docs mappings.
### Translations
- Added English labels for the new widget options:
- `widget.timetable.option.baseUrl.label`
- `widget.releases.option.repositories.providerUrl.label`
## How It Works Now
Release provider configuration lives on each Releases widget repository entry. The request handler resolves provider metadata and fetches releases directly from the provider-specific endpoint. GHCR uses anonymous OCI registry access for public packages.
Timetable passes its widget URL option directly to its API router and request handler. No global integration lookup is needed.
ArchiveTeam Warrior continues to use the standard integration system, but users must manually add the integration (it is not auto-created on install).
## Deliberate Non-Goals
- No provider secret/token support was added.
- No new secret storage model was introduced.
- No compatibility layer was kept in `packages/integrations`.
Widget options are client-visible, so storing provider credentials there would be wrong. If authenticated provider requests are needed later, they need a separate secret-storage design.
## Verification So Far
- Focused typechecks passed for affected packages.
- Full `pnpm turbo typecheck` passed.
- Full `pnpm lint` passed with existing warnings.
- Focused release provider normalization tests passed.
- Widget translation test passed.
- Live GHCR smoke checks passed for `ghcr.io/muchobien/pocketbase:latest` and `ghcr.io/homarr-labs/homarr:latest`.
- `pnpm test packages/integrations/test/pi-hole.spec.ts` passed earlier, but failed on rebased reruns because Pi-hole reported `domainsBeingBlocked` as `-2`/`0` instead of `> 1`.
+222 -1
View File
@@ -1,7 +1,228 @@
# ── CODEOWNERS ───────────────────────────────────────
* @homarr-labs/maintainers
# Exempt Renovate‑managed files (no owners)
# Specific features / integrations
# These owners come from the PR that introduced each integration implementation.
# Specific rules override the global fallback because CODEOWNERS uses the last
# matching pattern; do not include @homarr-labs/maintainers here unless they
# should also be requested for that integration.
# AdGuard Home - introduced in https://github.com/homarr-labs/homarr/pull/929 by @hillaliy
apps/docs/docs/integrations/adguard-home @hillaliy
packages/integrations/src/adguard-home @hillaliy
# Anchor - introduced in https://github.com/homarr-labs/homarr/pull/5040 by @ohmzi
apps/docs/docs/integrations/anchor @ohmzi
packages/integrations/src/anchor @ohmzi
# ArchiveTeam Warrior - introduced in https://github.com/homarr-labs/homarr/pull/5784 by @darbyjack
apps/docs/docs/integrations/archive-team-warrior @darbyjack
packages/integrations/src/archive-team-warrior @darbyjack
# Bazarr - introduced in https://github.com/homarr-labs/homarr/pull/6156 by @Ayush7614
apps/docs/docs/integrations/bazarr @Ayush7614
apps/docs/docs/widgets/bazarr @Ayush7614
packages/api/src/router/widgets/bazarr.ts @Ayush7614
packages/integrations/src/bazarr @Ayush7614
packages/request-handler/src/bazarr.ts @Ayush7614
packages/widgets/src/bazarr @Ayush7614
# Audiobookshelf - introduced in https://github.com/homarr-labs/homarr/pull/5910 by @ajnart
apps/docs/docs/integrations/audiobookshelf @ajnart
packages/integrations/src/audiobookshelf @ajnart
# Beszel - introduced in https://github.com/homarr-labs/homarr/pull/5900 by @ajnart
apps/docs/docs/integrations/beszel @ajnart
packages/integrations/src/beszel @ajnart
# Codeberg - introduced in https://github.com/homarr-labs/homarr/pull/3253 by @Aandree5
apps/docs/docs/integrations/codeberg @Aandree5
packages/integrations/src/codeberg @Aandree5
# Coolify - introduced in https://github.com/homarr-labs/homarr/pull/4789 by @Rhiz3K
apps/docs/docs/integrations/coolify @Rhiz3K
packages/integrations/src/coolify @Rhiz3K
# Dash. - introduced in https://github.com/homarr-labs/homarr/pull/1541 by @manuel-rw
apps/docs/docs/integrations/dash-dot @manuel-rw
packages/integrations/src/dashdot @manuel-rw
# Docker Hub - introduced in https://github.com/homarr-labs/homarr/pull/3253 by @Aandree5
apps/docs/docs/integrations/docker-hub @Aandree5
packages/integrations/src/docker-hub @Aandree5
# Emby - introduced in https://github.com/homarr-labs/homarr/pull/2466 by @Meierschlumpf
apps/docs/docs/integrations/emby @Meierschlumpf
packages/integrations/src/emby @Meierschlumpf
# GitHub - introduced in https://github.com/homarr-labs/homarr/pull/3253 by @Aandree5
apps/docs/docs/integrations/github @Aandree5
packages/integrations/src/github @Aandree5
# GitHub Container Registry - introduced in https://github.com/homarr-labs/homarr/pull/3727 by @Aandree5
apps/docs/docs/integrations/github-containerregistry @Aandree5
packages/integrations/src/github-container-registry @Aandree5
# GitLab - introduced in https://github.com/homarr-labs/homarr/pull/3253 by @Aandree5
apps/docs/docs/integrations/gitlab @Aandree5
packages/integrations/src/gitlab @Aandree5
# Glances - introduced in https://github.com/homarr-labs/homarr/pull/5102 by @manuel-rw
apps/docs/docs/integrations/glances @manuel-rw
packages/integrations/src/glances @manuel-rw
# Gluetun - introduced in https://github.com/homarr-labs/homarr/pull/5812 by @Lok3sh-kumar
apps/docs/docs/integrations/gluetun @Lok3sh-kumar
packages/integrations/src/gluetun @Lok3sh-kumar
# Gotify - introduced in https://github.com/homarr-labs/homarr/pull/5847 by @Nerdy-Technician
apps/docs/docs/integrations/gotify @Nerdy-Technician
packages/integrations/src/gotify @Nerdy-Technician
# Home Assistant - introduced in https://github.com/homarr-labs/homarr/pull/578 by @manuel-rw
apps/docs/docs/integrations/home-assistant @manuel-rw
packages/integrations/src/homeassistant @manuel-rw
# ICal - introduced in https://github.com/homarr-labs/homarr/pull/3980 by @NicolasNewman
apps/docs/docs/integrations/ical @NicolasNewman
packages/integrations/src/ical @NicolasNewman
# Immich - introduced in https://github.com/homarr-labs/homarr/pull/5165 by @manuel-rw
apps/docs/docs/integrations/immich @manuel-rw
packages/integrations/src/immich @manuel-rw
# Jellyfin - introduced in https://github.com/homarr-labs/homarr/pull/672 by @manuel-rw
apps/docs/docs/integrations/jellyfin @manuel-rw
packages/integrations/src/jellyfin @manuel-rw
# Jellyseerr - introduced in https://github.com/homarr-labs/homarr/pull/774 by @manuel-rw
apps/docs/docs/integrations/jellyseerr @manuel-rw
packages/integrations/src/jellyseerr @manuel-rw
# LinuxServer.io - introduced in https://github.com/homarr-labs/homarr/pull/3607 by @Aandree5
apps/docs/docs/integrations/linux-server-io @Aandree5
packages/integrations/src/linuxserverio @Aandree5
# Navidrome - introduced in https://github.com/homarr-labs/homarr/pull/5910 by @ajnart
apps/docs/docs/integrations/navidrome @ajnart
packages/integrations/src/navidrome @ajnart
# Nextcloud - introduced in https://github.com/homarr-labs/homarr/pull/2501 by @manuel-rw
apps/docs/docs/integrations/nextcloud @manuel-rw
packages/integrations/src/nextcloud @manuel-rw
# npm - introduced in https://github.com/homarr-labs/homarr/pull/3253 by @Aandree5
apps/docs/docs/integrations/npm @Aandree5
packages/integrations/src/npm @Aandree5
# ntfy - introduced in https://github.com/homarr-labs/homarr/pull/2900 by @itzTheMeow
apps/docs/docs/integrations/ntfy @ajnart @manuel-rw
packages/integrations/src/ntfy @ajnart @manuel-rw
# OpenMediaVault - introduced in https://github.com/homarr-labs/homarr/pull/1142 by @hillaliy
apps/docs/docs/integrations/open-media-vault @hillaliy
packages/integrations/src/openmediavault @hillaliy
# OPNsense - introduced in https://github.com/homarr-labs/homarr/pull/3424 by @Oupsman
apps/docs/docs/integrations/opnsense @Oupsman
packages/integrations/src/opnsense @Oupsman
# Overseerr - introduced in https://github.com/homarr-labs/homarr/pull/774 by @manuel-rw
apps/docs/docs/integrations/overseerr @manuel-rw
packages/integrations/src/overseerr @manuel-rw
# Paperless-ngx - introduced in https://github.com/homarr-labs/homarr/pull/5910 by @ajnart
apps/docs/docs/integrations/paperless-ngx @ajnart
packages/integrations/src/paperless-ngx @ajnart
# PatchMon - introduced in https://github.com/homarr-labs/homarr/pull/6119 by @mrjoshuap
apps/docs/docs/integrations/patchmon @mrjoshuap
packages/integrations/src/patchmon @mrjoshuap
packages/widgets/src/patchmon @mrjoshuap
packages/api/src/router/widgets/patchmon.ts @mrjoshuap
packages/request-handler/src/patchmon.ts @mrjoshuap
# PeaNUT - introduced in https://github.com/homarr-labs/homarr/pull/5862 by @afonsojramos
apps/docs/docs/integrations/peanut @afonsojramos
packages/integrations/src/peanut @afonsojramos
# Pi-hole - introduced in https://github.com/homarr-labs/homarr/pull/521 by @Meierschlumpf
apps/docs/docs/integrations/pi-hole @Meierschlumpf
packages/integrations/src/pi-hole @Meierschlumpf
# Plex - introduced in https://github.com/homarr-labs/homarr/pull/1342 by @hillaliy
apps/docs/docs/integrations/plex @hillaliy
packages/integrations/src/plex @hillaliy
# Prowlarr - introduced in https://github.com/homarr-labs/homarr/pull/965 by @hillaliy
apps/docs/docs/integrations/prowlarr @hillaliy
packages/integrations/src/prowlarr @hillaliy
# Proxmox - introduced in https://github.com/homarr-labs/homarr/pull/1969 by @Meierschlumpf
apps/docs/docs/integrations/proxmox @Meierschlumpf
packages/integrations/src/proxmox @Meierschlumpf
# Quay - introduced in https://github.com/homarr-labs/homarr/pull/3607 by @Aandree5
apps/docs/docs/integrations/quay @Aandree5
packages/integrations/src/quay @Aandree5
# search.ch - introduced in https://github.com/homarr-labs/homarr/pull/5180 by @Meierschlumpf
apps/docs/docs/integrations/search-ch @Meierschlumpf
packages/integrations/src/search-ch @Meierschlumpf
# Speedtest Tracker - introduced in https://github.com/homarr-labs/homarr/pull/5363 by @kylegrieder
apps/docs/docs/integrations/speedtest-tracker @kylegrieder
packages/integrations/src/speedtest-tracker @kylegrieder
# Synology - introduced in https://github.com/homarr-labs/homarr/pull/6121 by @mrjoshuap
apps/docs/docs/integrations/synology @mrjoshuap
packages/integrations/src/synology @mrjoshuap
# Technitium DNS - introduced in https://github.com/homarr-labs/homarr/pull/5832 by @lopsch
apps/docs/docs/integrations/technitium-dns @lopsch
packages/integrations/src/technitium @lopsch
# Tracearr - introduced in https://github.com/homarr-labs/homarr/pull/5060 by @StrandedTurtle
apps/docs/docs/integrations/tracearr @StrandedTurtle
packages/integrations/src/tracearr @StrandedTurtle
# TrueNAS - introduced in https://github.com/homarr-labs/homarr/pull/3745 by @manuel-rw
apps/docs/docs/integrations/truenas @manuel-rw @afonsojramos
packages/integrations/src/truenas @manuel-rw @afonsojramos
# Umami - introduced in https://github.com/homarr-labs/homarr/pull/5362 by @febrile42
apps/docs/docs/integrations/umami @febrile42
packages/integrations/src/umami @febrile42
# UniFi Controller - introduced in https://github.com/homarr-labs/homarr/pull/2236 by @pitschi
apps/docs/docs/integrations/unifi-controller @pitschi
packages/integrations/src/unifi-controller @pitschi
# Unraid - introduced in https://github.com/homarr-labs/homarr/pull/4439 by @manuel-rw
apps/docs/docs/integrations/unraid @manuel-rw
packages/integrations/src/unraid @manuel-rw
# Uptime Kuma - introduced in https://github.com/homarr-labs/homarr/pull/5910 by @ajnart
apps/docs/docs/integrations/uptime-kuma @ajnart
packages/integrations/src/uptime-kuma @ajnart
# What's Up Docker (WUD) - introduced in https://github.com/homarr-labs/homarr/pull/6523 by @tiimonn
apps/docs/docs/integrations/whats-up-docker @tiimonn
apps/docs/docs/widgets/whats-up-docker @tiimonn
packages/api/src/router/widgets/wud.ts @tiimonn
packages/integrations/src/wud @tiimonn
packages/request-handler/src/wud.ts @tiimonn
packages/widgets/src/wud @tiimonn
# Traefik - by @Nerdy-Technician
apps/docs/docs/integrations/traefik @Nerdy-Technician
apps/docs/docs/widgets/traefik @Nerdy-Technician
packages/api/src/router/widgets/traefik.ts @Nerdy-Technician
packages/integrations/src/traefik @Nerdy-Technician
packages/request-handler/src/traefik.ts @Nerdy-Technician
packages/widgets/src/traefik @Nerdy-Technician
# Exempt Renovate-managed files (no owners)
package.json
**/package.json
package-lock.json
+43 -12
View File
@@ -1,24 +1,53 @@
FROM node:24.16.0-alpine AS base
# syntax=docker/dockerfile:1.25
FROM node:24.18.0-alpine AS base
FROM base AS builder
RUN apk add --no-cache libc6-compat
RUN apk update
# Set working directory
ARG TARGETPLATFORM
WORKDIR /app
RUN apk add --no-cache libc6-compat curl bash
RUN apk update
# Native dependencies normally use prebuilds, but the build must remain
# reproducible when a prebuild download times out and compilation is required.
RUN apk add --no-cache libc6-compat curl bash python3 make g++
RUN corepack enable pnpm
COPY .npmrc pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY patches ./patches
COPY --parents ./apps/*/package.json ./packages/*/package.json ./tooling/*/package.json ./
# @homarr/definitions generates documentation types during install.
COPY --parents ./packages/definitions/src ./
# Workaround for pnpm/pnpm#5268: pnpm fetch crashes when patchedDependencies
# are configured with nodeLinker: hoisted. The applyPatchToDir function tries
# to chdir into node_modules/<pkg> which doesn't exist during fetch (only the
# content-addressable store is populated). By temporarily switching to the
# isolated linker, patches apply inside the virtual store (node_modules/.pnpm/...)
# which IS created by pnpm fetch. The original hoisted linker is restored
# before the install step so the final node_modules layout stays flat.
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store \
pnpm config set store-dir /pnpm/store && \
sed -i 's/nodeLinker: hoisted/nodeLinker: isolated/' pnpm-workspace.yaml && \
pnpm fetch --ignore-scripts && \
sed -i 's/nodeLinker: isolated/nodeLinker: hoisted/' pnpm-workspace.yaml
# Install only from the fetched, committed lockfile so local and Docker builds
# resolve the same dependency graph. Serial lifecycle builds avoid esbuild's
# atomic binary replacement racing across the hoisted workspace (pnpm/pnpm#8200).
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store \
npm_config_nodedir=/usr/local pnpm install --recursive --offline --frozen-lockfile --child-concurrency=1
COPY . .
RUN corepack enable pnpm && pnpm install --recursive --frozen-lockfile
# Copy static data as it is not part of the build
COPY static-data ./static-data
ARG SKIP_ENV_VALIDATION='true'
ARG CI='true'
ARG DISABLE_REDIS_LOGS='true'
ARG TARGETPLATFORM
RUN corepack enable pnpm && pnpm build
RUN --mount=type=secret,id=TURBO_API,env=TURBO_API \
--mount=type=secret,id=TURBO_TEAM,env=TURBO_TEAM \
--mount=type=secret,id=TURBO_TOKEN,env=TURBO_TOKEN \
--mount=type=secret,id=TURBO_REMOTE_CACHE_SIGNATURE_KEY,env=TURBO_REMOTE_CACHE_SIGNATURE_KEY \
--mount=type=cache,id=homarr-next-build-${TARGETPLATFORM},target=/app/apps/nextjs/.next/cache,sharing=locked \
TURBO_PLATFORM="${TARGETPLATFORM:-linux/amd64}" \
pnpm turbo build --filter=@homarr/nextjs... --filter=@homarr/cli
FROM base AS runner
WORKDIR /app
@@ -42,6 +71,7 @@ RUN mkdir -p /var/cache/nginx && \
COPY --from=builder /app/apps/nextjs/next.config.ts .
COPY --from=builder /app/apps/nextjs/package.json .
COPY --from=builder /app/pnpm-workspace.yaml ./pnpm-workspace.yaml
COPY --from=builder /app/node_modules/better-sqlite3/build/Release/better_sqlite3.node /app/build/better_sqlite3.node
@@ -65,5 +95,6 @@ ENV AUTH_PROVIDERS='credentials'
ENV REDIS_IS_EXTERNAL='false'
ENV NODE_ENV='production'
EXPOSE 7575
ENTRYPOINT [ "/app/entrypoint.sh" ]
CMD ["sh", "run.sh"]
-3
View File
@@ -23,9 +23,6 @@
"react-hooks/exhaustive-deps": "warn",
"eslint/no-unused-expressions": "warn"
},
"options": {
"reportUnusedDisableDirectives": "off"
},
"ignorePatterns": ["**/*.config.js", "**/*.config.mjs", "**/*.cjs", ".docusaurus/**", "build/**"],
"settings": {
"react": { "version": "19" }
+2 -2
View File
@@ -55,8 +55,8 @@ pnpm typecheck
docs/
├── getting-started/ # Installation guides, glossary, prerequisites
├── management/ # Boards, apps, users, integrations, settings, tasks, API
├── integrations/ # 55 integration guides (one folder each)
├── widgets/ # 42 widget guides (one folder each)
├── integrations/ # 56 integration guides (one folder each)
├── widgets/ # 43 widget guides (one folder each)
├── advanced/ # SSO, env vars, proxy, styling, CLI, development
└── community/ # FAQ, donate, license, translations, get-in-touch
```
@@ -0,0 +1,41 @@
# Developer Docker CLI
The host-side developer CLI builds and runs local Homarr images and pull-request previews. Run it directly from a checkout with `pnpm dev:cli -- ...`; no shell-specific setup script is required. It is separate from the recovery CLI included in production images.
To install an optional `homarr` binary, run `pnpm dev:cli:install` and make your Go bin directory available on `PATH`. GitHub CLI authentication is only needed for pull-request features.
## Browse development images
```bash
pnpm dev:cli --
```
The main screen combines local `homarr:*` images with open pull requests and their GHCR preview status. Select an image to start or stop it, use `R` to build a remote pull request locally in the background or rebuild a local image, or use `p` to force a remote preview pull. Press `d` to switch to the instance dashboard and `d` again to return without losing the browser state. The explicit `dev` and `dash` subcommands start on either screen.
A locally built PR image is folded into its remote PR row only when its recorded revision exactly matches the current GitHub head SHA. The row is marked `◆ local`, and starting it prefers that local image without a registry pull. Outdated local builds remain separate rows. Navigation and dashboard switching remain available during background builds.
## Build images
```bash
pnpm dev:cli -- build <name>
pnpm dev:cli -- build --pr <number> [name]
```
The first command builds the current checkout as `homarr:<name>`. The pull-request form uses a depth-one clone in a temporary directory and defaults to `homarr:pr-<number>` when `name` is omitted.
## Rebuild images
```bash
pnpm dev:cli -- rebuild <name>
```
Images built by this CLI record their source checkout, revision, and optional pull-request number. Rebuild uses that provenance to select the original checkout or create a fresh temporary pull-request checkout.
## Run images
```bash
homarr run <name>
homarr run --pr <number>
```
Add `--detach` to run in the background, `--demo` to enable demo data, or repeat `--env KEY=VALUE` to provide additional environment variables.
@@ -14,11 +14,12 @@ This guide will help you set up your development environment to start contributi
### Prerequisites
- **Node.js (lts)**: You can download it from the [official website](https://nodejs.org/).
- **pnpm (latest)**: You can install it by running `npm install -g pnpm`.
- **Node.js 24.18 or newer**: You can download it from the [official website](https://nodejs.org/).
- **Corepack**: Run `corepack enable` so the repository selects its pinned pnpm version.
- **Git**: You can download it from the [official website](https://git-scm.com/).
- **Docker or Docker Desktop**: You can download it from the [official website](https://www.docker.com/).
- **A GitHub account**: You can create one on the [official website](https://github.com/).
- **Docker or Docker Desktop**: Required for the Redis service and the developer Docker CLI.
- **Go 1.25+**: Required only for the developer Docker CLI. You can download it from the [official website](https://go.dev/).
- **GitHub CLI**: Required only for pull-request image features. Install it from the [official website](https://cli.github.com/), then authenticate with `gh auth login`.
### Setting up the project
@@ -34,11 +35,11 @@ This guide will help you set up your development environment to start contributi
4. Install the dependencies with `pnpm install`.
5. Start redis by running `pnpm run docker:dev`. This will run a docker-compose file with a redis service.
5. Create `.env` from `.env.example`. In a POSIX shell, run `cp .env.example .env`; in PowerShell, run `Copy-Item .env.example .env`. Set `DB_URL` to an absolute path for your SQLite file.
6. 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='C:\\Dev\\homarr\\packages\\db\\db.sqlite'`
6. Start Redis in the background with `pnpm docker:dev:up` if your development workflow needs it.
7. Run the migrations to create the sqlite db file with `pnpm run db:migration:sqlite:run`.
7. Create or update the database with `pnpm db:migration:sqlite:run`. This also seeds the default data. To run the seed explicitly later, use `pnpm db:seed`.
8. Start the development server with `pnpm dev` and wait for a message that says `✓ Ready in 10.7s`
@@ -48,9 +49,19 @@ This guide will help you set up your development environment to start contributi
#### During development
- `pnpm dev`: Start the development server.
- `pnpm dev`: Start the Next.js development server.
- `pnpm dev:benchmark`: Run the local authenticated-board benchmark. Set `DEV_BENCHMARK_BOARD_URL` and
`DEV_BENCHMARK_STORAGE_STATE`; readiness-only measurements require the explicit `--smoke` flag and are not
suitable for performance claims.
- `pnpm dev:cli -- dev`: Browse and run local images and remote pull-request images.
- `pnpm dev:cli -- build <name>`: Build the current checkout as `homarr:<name>`.
- `pnpm dev:cli -- build --pr <number>`: Build a pull request locally from a temporary checkout.
- `pnpm dev:cli -- rebuild <name>`: Rebuild a local image from its recorded checkout or pull request.
- `pnpm dev:cli:install`: Optionally install the developer CLI as a `homarr` binary.
- `pnpm cli`: Run cli commands.
- `pnpm db:migration:sqlite:run`: Run the migrations to create or update the sqlite db file.
- `pnpm db:seed`: Explicitly seed the default database data.
- `pnpm docker:dev:up`: Start the Redis development service in the background.
- `pnpm db:migration:sqlite:generate`: Generate a new migration file for the sqlite db. Also works with `mysql`.
- `pnpm db:studio`: Open a visual studio for the database.
- `pnpm package:new`: Create a new package in the monorepo.
@@ -63,6 +74,8 @@ This guide will help you set up your development environment to start contributi
- `pnpm typecheck`: Run the typescript type checker.
#### Building the project
- `pnpm build`: Build the project for production.
- `pnpm dev:cli -- build <name>`: Build a `homarr:<name>` image and record its checkout for later rebuilds.
- `docker build -t homarr .`: Build a docker image for the project.
- `docker run -p 7575:7575 -e SECRET_ENCRYPTION_KEY='your_64_character_hex_string' homarr:latest`: Run the created docker image.
- `docker run -p 7575:7575 -e SECRET_ENCRYPTION_KEY='your_64_character_hex_string' homarr:<name>`: Run the created docker image.
@@ -25,15 +25,14 @@ This is especially useful for [docker secrets](https://docs.docker.com/engine/sw
Using the `PUID` and `PGID` will require you to set the correct permissions on the mounted volumes and if used the docker socket. See more in the [Running as a different user](/docs/advanced/running-as-different-user) documentation.
:::
| Environment Variable | Description | Possible values | Default |
| ------------------------ | ----------- | --------------- | ------- |
| ``PUID`` | User ID to run the container as | Any valid user ID | ``0`` |
| ``PGID`` | Group ID to run the container as | Any valid group ID | ``0`` |
| ``LOG_LEVEL`` | Log level to use | ``debug`` / ``info`` / ``warn`` / ``error`` | ``info`` |
| ``NO_EXTERNAL_CONNECTION`` | Disables some requests that need internet connection | `true` or `false` | `false` |
| ``ENABLE_DNS_CACHING`` | Enables dns caching. Enabled by default, but if you experience issues with IPv6 or static IPs, see [#4006](https://github.com/homarr-labs/homarr/issues/4006) or disable this flag | `true` or `false` | `true` |
| Environment Variable | Description | Possible values | Default |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ------- |
| `PUID` | User ID to run the container as | Any valid user ID | `0` |
| `PGID` | Group ID to run the container as | Any valid group ID | `0` |
| `LOG_LEVEL` | Log level to use | `debug` / `info` / `warn` / `error` | `info` |
| `NO_EXTERNAL_CONNECTION` | Disables Homarr's internet-backed requests, including update checks, weather, and RSS feeds | `true` or `false` | `false` |
| `ENABLE_DNS_CACHING` | Enables dns caching. Enabled by default, but if you experience issues with IPv6 or static IPs, see [#4006](https://github.com/homarr-labs/homarr/issues/4006) or disable this flag | `true` or `false` | `true` |
| `HOMARR_DISABLE_IPV6` | Disables the IPv6 listener of the internal nginx proxy, even when the host supports IPv6. IPv6 is normally disabled automatically when the host has no IPv6 configured. See [#4596](https://github.com/homarr-labs/homarr/issues/4596) | `true` or `false` | `false` |
## Authentication
@@ -43,9 +42,9 @@ See [Single Sign-On](/docs/advanced/single-sign-on) for more informations.
The `SECRET_ENCRYPTION_KEY` is required. If none is specified before starting the container, a random key will be shown in the error message and the container will exit.
| Environment Variable | Description | Possible values | Default |
| ------------------------ | ----------- | --------------- | ------- |
| ``SECRET_ENCRYPTION_KEY`` | Secret used to encrypt secrets in database. | 64 character hex string | - |
| Environment Variable | Description | Possible values | Default |
| ----------------------- | ------------------------------------------- | ----------------------- | ------- |
| `SECRET_ENCRYPTION_KEY` | Secret used to encrypt secrets in database. | 64 character hex string | - |
:::info
A random secret can be generated by using the following command: `openssl rand -hex 32`
@@ -53,27 +52,27 @@ A random secret can be generated by using the following command: `openssl rand -
## Docker
| Environment Variable | Description | Possible values | Default |
| ------------------------ | ----------- | --------------- | ------- |
| ``DOCKER_HOSTNAMES`` | Comma seperated list of hostnames to connect to | For example `localhost,docker.example.com` | - |
| ``DOCKER_PORTS`` | Comma seperated list of ports to connect to | For example `2375,2376` | - |
| ``DOCKER_SOCKET_PATHS`` | Comma seperated list of paths to sockets | For example `/var/run/docker.sock,/run/user/1000/podman/podman.sock` | - |
| Environment Variable | Description | Possible values | Default |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------- |
| `DOCKER_HOSTNAMES` | Comma-separated list of hostnames to connect to | For example `localhost,docker.example.com` | - |
| `DOCKER_PORTS` | Comma-separated list of ports to connect to | For example `2375,2376` | - |
| `DOCKER_SOCKET_PATHS` | Comma-separated list of mounted Docker-compatible socket paths. See the [Docker and Podman integration guide](/docs/integrations/docker) | For example `/var/run/docker.sock,/var/run/podman.sock` | - |
## Database
| Environment Variable | Description | Possible values | Default |
| ------------------------ | ----------- | --------------- | ------- |
| ``DB_DRIVER`` | Database driver to use. Currently `better-sqlite3` is used for sqlite, `mysql2` for mysql and `node-postgres` for postgresql | ``better-sqlite3`` / ``mysql2`` / ``node-postgres`` | ``better-sqlite3`` |
| ``DB_DIALECT`` | Database dialect to use. | ``sqlite`` / ``mysql`` / ``postgresql`` | ``sqlite`` |
| ``DB_URL`` | Database URL to connect to. | Any valid database URL | ``/appdata/db/db.sqlite`` |
| ``DB_HOST`` | Database host to connect to. | Any valid database host | - |
| ``DB_PORT`` | Database port to connect to. | Any valid database port | - |
| ``DB_NAME`` | Database name to connect to. | Any valid database name | - |
| ``DB_USER`` | Database user to connect with. | Any valid database user | - |
| ``DB_PASSWORD`` | Database password to connect with. | Any valid database password | - |
| Environment Variable | Description | Possible values | Default |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | ----------------------- |
| `DB_DRIVER` | Database driver to use. Currently `better-sqlite3` is used for sqlite, `mysql2` for mysql and `node-postgres` for postgresql | `better-sqlite3` / `mysql2` / `node-postgres` | `better-sqlite3` |
| `DB_DIALECT` | Database dialect to use. | `sqlite` / `mysql` / `postgresql` | `sqlite` |
| `DB_URL` | Database URL to connect to. | Any valid database URL | `/appdata/db/db.sqlite` |
| `DB_HOST` | Database host to connect to. | Any valid database host | - |
| `DB_PORT` | Database port to connect to. | Any valid database port | - |
| `DB_NAME` | Database name to connect to. | Any valid database name | - |
| `DB_USER` | Database user to connect with. | Any valid database user | - |
| `DB_PASSWORD` | Database password to connect with. | Any valid database password | - |
You can either use the url or host, port, name and credentials combined. The URL will be prioritized over the other values.
## Redis
By default Redis is running within the installation. (for example in Docker).
@@ -83,25 +82,23 @@ However for example for K8s it can be useful to use an external Redis instance.
External redis is currently not supported with Proxmox Community Scripts
:::
| Environment Variable | Description | Possible values | Default |
| ------------------------ | ----------- | --------------- | ------- |
| `REDIS_IS_EXTERNAL` | Whether Redis is running externally. | `true` / `false` | `false` |
| `REDIS_HOST` | Hostname of the Redis instance. | Any valid hostname | - |
| `REDIS_PORT` | Port of the Redis instance. | Any valid port | `6379` |
| `REDIS_USERNAME` | Username to connect to the Redis instance. | Any valid username | - |
| `REDIS_PASSWORD` | Password to connect to the Redis instance. | Any valid password | - |
| `REDIS_DATABASE_INDEX` | Select which database of your redis instance should be used. | Any numeric index | - |
| `REDIS_TLS_CA` | CA certificate for Redis TLS connections. If a certificate is specified the connection will use TLS. | Any valid CA certificate | - |
| Environment Variable | Description | Possible values | Default |
| ---------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------ | ------- |
| `REDIS_IS_EXTERNAL` | Whether Redis is running externally. | `true` / `false` | `false` |
| `REDIS_HOST` | Hostname of the Redis instance. | Any valid hostname | - |
| `REDIS_PORT` | Port of the Redis instance. | Any valid port | `6379` |
| `REDIS_USERNAME` | Username to connect to the Redis instance. | Any valid username | - |
| `REDIS_PASSWORD` | Password to connect to the Redis instance. | Any valid password | - |
| `REDIS_DATABASE_INDEX` | Select which database of your redis instance should be used. | Any numeric index | - |
| `REDIS_TLS_CA` | CA certificate for Redis TLS connections. If a certificate is specified the connection will use TLS. | Any valid CA certificate | - |
## Proxy
| Environment Variable | Description | Possible values | Default |
| ------------------------ | ----------- | --------------- | ------- |
| ``HTTP_PROXY`` | HTTP proxy to use | Any valid HTTP proxy URL | - |
| ``HTTPS_PROXY`` | HTTPS proxy to use | Any valid HTTPS proxy URL | - |
| ``NO_PROXY`` | Comma separated list of hosts that should be excluded from proxying | Any valid hostnames | - |
| Environment Variable | Description | Possible values | Default |
| -------------------- | ------------------------------------------------------------------- | ------------------------- | ------- |
| `HTTP_PROXY` | HTTP proxy to use | Any valid HTTP proxy URL | - |
| `HTTPS_PROXY` | HTTPS proxy to use | Any valid HTTPS proxy URL | - |
| `NO_PROXY` | Comma separated list of hosts that should be excluded from proxying | Any valid hostnames | - |
## Advanced deployments
@@ -109,6 +106,6 @@ External redis is currently not supported with Proxmox Community Scripts
The advanced deployments environment variables should only be used if you know what you are doing.
:::
| Environment Variable | Description |
| ------------------------ | ----------- |
| ``DB_MIGRATIONS_DISABLED`` | Disable db migrations. For example for helm charts |
| Environment Variable | Description |
| ------------------------ | -------------------------------------------------- |
| `DB_MIGRATIONS_DISABLED` | Disable db migrations. For example for helm charts |
+18 -9
View File
@@ -9,17 +9,19 @@ tags:
---
## Icon picker
Icons in Homarr are automatically requested from multiple sources:
- [Dashboard Icons](https://dashboardicons.com/) - Our recommended source with over 1888+ curated, high-quality icons
- [selfh.st icons](https://github.com/selfhst/icons)
- [Simple icons](https://github.com/simple-icons/simple-icons)
- [Tabler icons](https://tabler-icons.io/)
- [Papirus icons](https://github.com/PapirusDevelopmentTeam/papirus-icon-theme)
- [Homelab Svg assets](https://github.com/loganmarchione/homelab-svg-assets)
- **Local icons**: automatically fetched from the [medias feature](/docs/management/media/)
- [Dashboard Icons](https://dashboardicons.com/) - Our recommended source with more than 1,888 curated, high-quality icons
- [selfh.st icons](https://github.com/selfhst/icons)
- [Simple icons](https://github.com/simple-icons/simple-icons)
- [Tabler icons](https://tabler-icons.io/)
- [Papirus icons](https://github.com/PapirusDevelopmentTeam/papirus-icon-theme)
- [Homelab Svg assets](https://github.com/loganmarchione/homelab-svg-assets)
- **Local icons**: automatically fetched from the [medias feature](/docs/management/media/)
Using these icon sources, Homarr provides a total collection of over 11,000 icons at your fingertips.
The icon picker is a fast searcher that helps you to find your desired icon simply by entering a search term.
The image picker searches this collection after a short typing delay. When a name is available, such as an app or search engine name, the picker uses it as the initial search. Results show your locally uploaded images first, followed by SVG icons and then other image formats.
### Finding Missing Icons
@@ -29,6 +31,13 @@ If you can't find the icon you're looking for in Homarr's built-in picker, we st
Icons that are high quality and printable ([SVG](https://wikipedia.org/wiki/Scalable_Vector_Graphics)) are marked with a red badge "SVG" at the top right.
You can clear the selected image with the clear button or the usual keyboard shortcut for deleting a line (Command+Backspace on macOS or Control+Backspace on other platforms). Clearing the field does not restore the previous image.
### Using external icons
If you don't find the icon you're looking for on Dashboard Icons or wish to use a different source, you can simply enter a URL that points to an icon.
It is important that the URL directly points to the file without any advertisements or elements around it.
Direct HTTP(S) image URLs are used as entered instead of being searched in the built-in repositories. The picker previews the image and shows whether it loaded successfully. It is important that the URL directly points to the file without any advertisements or elements around it.
### Uploading a local image
Users with media upload permission can select **Upload image** next to the field. After the upload finishes, the new local image is selected immediately and is available at the top of future searches.
-1
View File
@@ -47,7 +47,6 @@ services:
traefik.http.routers.homarr.rule: Host(`your.internal.dns.address.here.com`)
traefik.http.routers.homarr.entrypoints: websecure
traefik.http.routers.homarr-secure.app: homarr
traefik.http.apps.homarr.loadbalancer.server.port: 7575
networks:
proxy:
@@ -127,6 +127,8 @@ Homarr supports multiple authentication options, from internal userbase (credent
If you'd rather manage group memberships for OIDC users locally (instead of via the IdP), set `AUTH_OIDC_GROUPS_LOCAL_MANAGEMENT=true`. While enabled, Homarr stops syncing OIDC users' group memberships from the groups claim, and admins can add/remove OIDC users on a group's members page. If you turn this back to `false`, the next login of each user resumes the regular sync and reconciles their groups with the IdP's claim again, which may remove memberships that were added manually while local management was enabled.
To let an existing credentials user also sign in with OIDC, set `AUTH_OIDC_ENABLE_DANGEROUS_CREDENTIALS_LINKING=true`. On the first OIDC sign-in, Homarr links a credentials user with the same email address instead of creating a second user. The user keeps their password login, local username and profile, groups, permissions, boards, settings, and API keys. OIDC profile and group claims do not overwrite the credentials-owned data. Homarr requires the OIDC profile to contain `email_verified: true` while this option is enabled. Only enable this when your OIDC provider verifies email addresses, because a matching email could otherwise be used to take over an existing account.
<details>
<summary>
Example Setup
@@ -204,6 +206,7 @@ Homarr supports multiple authentication options, from internal userbase (credent
| ``AUTH_OIDC_NAME_ATTRIBUTE_OVERWRITE`` | Overwrite name attribute. By default it will use preferred_username if it does not contain a `@` and otherwise name. | --- |
| ``AUTH_OIDC_FORCE_USERINFO`` | Force userinfo endpoint to be used for user information. | false |
| ``AUTH_OIDC_ENABLE_DANGEROUS_ACCOUNT_LINKING`` | Enable account linking for OIDC provider. This will link the OIDC accounts by email. Be sure that you have verified emails to prevent stealing accounts. | false |
| ``AUTH_OIDC_ENABLE_DANGEROUS_CREDENTIALS_LINKING`` | Link an OIDC identity to an existing credentials user with the same email. The credentials login and existing user data are preserved. Requires the OIDC profile to contain `email_verified: true`. | false |
| ``AUTH_OIDC_TOKEN_ENDPOINT_AUTH_METHOD`` | Override method for the token endpoint authentication. Supported values are `client_secret_basic`, `client_secret_post`, `client_secret_jwt` and `none`. | client_secret_basic |
### Permission System
@@ -28,6 +28,7 @@ Read our [glossary](/docs/getting-started/glossary) if you are new to Homarr.
Congratulations on installing Homarr. Now it's time to get yourself familiar with the concepts of Homarr and how to use it.
## Onboarding
The onboard will show the first time you start Homarr.
This process will help you with your first steps and adding some initial data, such as the administrator account.
@@ -45,50 +46,68 @@ You can either import a previous dashboard using the ZIP archive or start from s
You may refresh anytime and continue from a different device - the onboarding is saved immediately on the server for your convenience.
### Starting from scratch
Depending on your auth provider configuration you will either first see the admin user creation form or the external group creation form.
If credentials provider was selected, you'll be prompted to create an admin user for Homarr.
This user cannot be deleted and has full control over Homarr and all of it's boards.
You must choose an username and password (both can later be changed).
We enforce strict password requirements, when you enter your password, to protect your instance if you accidentially
expose it to the Internet.
<img src={imageStartFromScratchStepAdminUser} alt={"Screenshot form to create admin user"} width={300} />
Depending on your auth provider configuration you will either first see the admin user creation form or the external group creation form.
If the credentials provider was selected, you'll be prompted to create an admin user for Homarr.
This user cannot be deleted and has full control over Homarr and all of its boards.
You must choose a username and password (both can later be changed).
We enforce strict password requirements when you enter your password to protect your instance if you accidentally
expose it to the internet.
<img
src={imageStartFromScratchStepAdminUser}
alt={"Screenshot form to create admin user"}
width={300}
/>
If you selected external providers (such as LDAP or OIDC), you'll be prompted to create an admin group.
This group will be used to synchronize users from your provider to Homarr.
When a user is logged in through the provider the groups of him that match groups with any in Homarr will be added to the user.
The name of the group has to match exactly the name of the group in the provider.
This group will be used to synchronize users from your provider to Homarr.
When a user logs in through the provider, any of their groups that match groups in Homarr will be assigned to the user.
The name of the group must match exactly the name of the group in the provider.
<img src={imageStartFromScratchStepExternalAdminGroup} alt={"Screenshot form to create external admin group"} width={300} />
<img
src={imageStartFromScratchStepExternalAdminGroup}
alt={"Screenshot form to create external admin group"}
width={300}
/>
Next, you can configure some basic settings for Homarr. We recommend to leave all settings at default for most users.
Here you can also disable analytics. Please note that our analytics are completly anonymous and is fully compliant with GDPR and PECR.
<img src={imageStartFromScratchStepServerSettings} alt={"Screenshot of analytics and indexing settings in the onboarding"} width={300} />
<img
src={imageStartFromScratchStepServerSettings}
alt={"Screenshot of analytics and indexing settings in the onboarding"}
width={300}
/>
### Setting up integrations
After configuring server settings, the onboarding guides you through setting up your integrations.
#### Docker service discovery
If Docker is available (socket mounted), Homarr automatically detects running containers and matches them to known integration types.
Matching integrations are pre-selected in the integration list, saving you from manually picking each one.
#### URL templating
You can define a base URL template to auto-fill integration URLs in bulk.
Two modes are supported:
- **Subdomain mode** - e.g. `{app}.example.com` where `{app}` is replaced with the integration name
- **Port mode** - e.g. `192.168.1.1:{port}` where `{port}` is replaced with the integration's default port
#### API key helper links
For integrations that require API keys (such as Sonarr, Radarr, SABnzbd, or Seerr), a helper link opens the relevant settings page in the target application so you can quickly copy your key.
#### Creating apps from Docker containers
You can optionally auto-create bookmark apps for all discovered Docker containers, making them immediately available on your board.
:::note
Some niche and registry integrations (GitHub, npm, Docker Hub, GitLab, Codeberg, LinuxServer.io, GHCR, Quay, Search.ch) are hidden from the onboarding selection grid but remain available on the manage integrations page.
Release providers and Search.ch are configured directly in their widgets instead of the integrations page.
:::
@@ -97,30 +116,41 @@ The onboarding can no longer be started again.
From here you can click on one of the provided links to continue your journey.
We recommend you to continue with the section [creating your first board on this page](#creating-your-first-board).
<img src={imageStartFromScratchStepFinish} alt={"Screenshot of the finish onboarding process with links"} width={300} />
<img
src={imageStartFromScratchStepFinish}
alt={"Screenshot of the finish onboarding process with links"}
width={300}
/>
### Importing a ZIP from version before 1.0.0
This is recommended when you used Homarr before and want to re-import your data.
It is important that you first migrate correctly using [the list of breaking changes for 1.0](/blog/2024/09/23/version-1.0).
<img src={manageExportOldHomarr} alt="Export from old Homarr" style={{ maxWidth: 500 }} />
<img
src={manageExportOldHomarr}
alt="Export from old Homarr"
style={{ maxWidth: 500 }}
/>
**How to export and import data**
1. Navigate to your old Homarr, open your management pages, open the tools submenu and open ``Migrate to 1.0``.
1. Navigate to your old Homarr, open your management pages, open the tools submenu and open `Migrate to 1.0`.
2. Check the contents that you want to export. We recommend you to export all data.
3. Click on the export data button
4. Save the ZIP file, that is being downloaded, on your device. If you selected "integrations" or "users", you also get an encryption / decryption key.
Copy it and do not loose it!
5. Go to your new >1.0.0 Homarr instance and start the onboarding. Choose ``Import from Homarr before 1.0``
Copy it and do not loose it!
5. Go to your new >1.0.0 Homarr instance and start the onboarding. Choose `Import from Homarr before 1.0`
6. Drag and drop your previously downloaded ZIP archive into the file upload: <br/><img src={manageImportOldHomarrDropzone} style={{ maxWidth: 500 }} />
7. Next, choose the data that you want to import and how to import it. Since screen sizes were removed in 1.0, we create a new board for every screen size by default. We recommend you to only keep the best layout and adjust it later in 1.0.0 - but you can also import all of them and pick later.<br/><img src={manageImportOldHomarrChooseData} style={{ maxWidth: 500 }} />
8. If you previously exported integrations or users, you will be asked to decrypt the data safely using your obtained encryption token. Paste into the modal and confirm your action.<br/><img src={manageImportDecryptionToken} style={{ maxWidth: 500 }} />
9. Next, you can [follow the same setup as when starting from scratch](#starting-from-scratch). After you completed the onboarding, all of your data will be migrated and available.
## Creating your first board
In Homarr, you organize your apps and widgets on boards.
Boards can be organized using the interactive drag and drop.
Let's create your first board by navigating here: ``Manage`` > ``Boards`` > ``New board``:
Let's create your first board by navigating here: `Manage` > `Boards` > `New board`:
![](./img/manage-create-board-button.png)
A board must always have a name and can either be public or private.
@@ -133,12 +163,13 @@ Congratulations - you've just created your first board. You can see boards, that
![](./img/manage-view-board.png)
## Add your first app to Homarr
To add links to your dashboard, you must first add them as an "app".
Navigate to this page to add an app:
![](./img/manage-navigate-apps.png)
Next, click on the ``New app`` button. You'll need to provide a name and an icon to create an app.
Next, click on the `New app` button. You'll need to provide a name and an icon to create an app.
The name must be at least one character long but you can provide any image URL for the icon.
Homarr ships with over 11K icons - so you can just search by entering a search text instead.
@@ -149,8 +180,9 @@ After you created the app, you'll see in on the apps page:
![](./img/manage-created-app.png)
## Arrange and organize your board
Let's add your freshly created app, from the previous step, to the board.
To do this, edit your previously created board by clicking on the big ``Open board`` button:
To do this, edit your previously created board by clicking on the big `Open board` button:
![](./img/manage-view-board.png)
@@ -165,23 +197,38 @@ Here you have the following options in the header:
When entering the edit mode, you'll get some additional buttons to work with:
<img src={manageBoardHeaderEditMode} alt={"Screenshot of buttons in the edit mode"} width={200} />
<img
src={manageBoardHeaderEditMode}
alt={"Screenshot of buttons in the edit mode"}
width={200}
/>
- **Add item**: Click this button to add new elements to your page.
- **Exit edit mode**: Click this btuton to save your changes and exit edit mode.
To continue, click the option "New Item":
<img src={manageBoardHeaderAddItem} alt={"Screenshot of the add item menu"} width={200} />
<img
src={manageBoardHeaderAddItem}
alt={"Screenshot of the add item menu"}
width={200}
/>
Next, you can choose what item you'd like to add.
We will discuss the other options in the following sections - for now choose "App" to continue.
<img src={manageBoardHeaderChooseItem} alt={"Screenshot of choosing the app item in the modal"} width={300} />
<img
src={manageBoardHeaderChooseItem}
alt={"Screenshot of choosing the app item in the modal"}
width={300}
/>
As soon as you chose the app, the modal will close and you'll get the following item on your board:
<img src={manageBoardNoApp} alt="Screenshot of the No app element on the board" />
<img
src={manageBoardNoApp}
alt="Screenshot of the No app element on the board"
/>
This is expected, because you haven't told Homarr what app it should show in this item.
To configure this, click on the small 3 dots at the top of the item in the edit mode and choose "Edit item" in the menu.
@@ -228,17 +275,18 @@ Be sure to save your changes by exiting edit mode!
![](./img/exit-edit-mode.png)
## Adding your first integration
Now it's time to integrate some basic data into your board.
To do this, we first need to create an integration.
An integration is a connection between Homarr and a third party application - usually something that you run and deploy yourself.
Navigate to ``Manage`` > ``Integrations`` (for example via your user menu).
Navigate to `Manage` > `Integrations` (for example via your user menu).
As an example, we are going to use the public demo instance of **Dash.** - a popular application to monitor CPU / hardware usage.
Choose the **Dash.** integration from the list of available integrations:
![](./img/choose-integration.gif)
Next, choose a name (or leave it at default), enter ``https://dash.mauz.dev/`` as the URL in the form and click on ``Test connection and create``.
Next, choose a name (or leave it at default), enter `https://dash.mauz.dev/` as the URL in the form and click on `Test connection and create`.
Pressing the save button will perform a test request to the integration, to confirm that the networking setup is working as expected.
Sometimes invalid configurations, firewalls and other mistakes can lead to connectivity problems - [follow this guide here](/docs/management/integrations/#troubleshooting-connection) if you experience issues.
@@ -254,13 +302,14 @@ the target application or your router.
:::
## Embed integration data using widgets
Let's add your integration, that you have configured in the section above, as a widget to your board.
First, navigate back to your board that you want to add it to.
Next, enter edit mode again and add another item to your board:
![](./img/manage-board-header-add-item-menu.png)
Instead of choosing an app, let's choose ``System Health Monitoring`` this time.
Instead of choosing an app, let's choose `System Health Monitoring` this time.
Click on "Add to board":
![](./img/manage-board-header-choose-system-health.png)
@@ -290,10 +339,12 @@ As with every change, don't forget to save your changes using the exit edit mode
![](./img/exit-edit-mode.png)
## Grouping your items
As the last step, let's organize your freshly created items using two different options.
You can choose either or both of them on your boards.
### Using dynamic sections
Dynamic sections are a simple, resizable visual group to group items.
![](./img/create-dynamic-section.png)
@@ -303,6 +354,7 @@ After adding a dynamic section, you can simply drag and drop items into the sect
![](./img/dynamic-section.gif)
### Using categories
Categories are more advanced and complicated than dynamic sections.
To create a category, open the add item modal and choose "new category":
@@ -329,22 +381,27 @@ You cannot reduce their horizontal width.
After completing the onboarding, Homarr provides interactive guided tours to help you discover key features.
### Management tour
When you first visit the management area (`/manage`), Homarr walks you through the main pages: boards, apps, integrations, and users (admin only).
Each page highlights the list view and the create action so you know where to find and add things.
### Board tour
When you first open a board, a tour highlights the board header elements: search, edit mode, settings, board switcher, and user menu.
### Tour controls
- Press **Enter** (or click **Next**) to advance through tour steps
- Tours auto-start on first visit and do not repeat once completed
- Tours are skipped on mobile screens (below `sm` breakpoint)
- You can **reset tours** from the user settings page under **Manage > Users > [Your user] > General**
## Next steps
You're done with the basic setup 🔥. Now it's time to organize and customize even more.
We highly recommend you to experiment with different options, styles and configurations.
See these curated pages for your next steps:
- Create new apps using the [apps management](/docs/management/apps/)
- Customize your board or add more boards using the [boards management](/docs/management/boards/)
- Integrate software that you use using the [integrations management](/docs/management/integrations/)
@@ -2,9 +2,9 @@
<img src="https://raw.githubusercontent.com/homarr-labs/charts/refs/heads/main/charts/homarr/icon.svg" align="right" width="92" alt="homarr logo">
![Version: 8.19.0](https://img.shields.io/badge/Version-8.19.0-informational?style=flat)
![Version: 8.28.1](https://img.shields.io/badge/Version-8.28.1-informational?style=flat)
![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat)
![AppVersion: v1.60.0](https://img.shields.io/badge/AppVersion-v1.60.0-informational?style=flat)
![AppVersion: v1.76.1](https://img.shields.io/badge/AppVersion-v1.76.1-informational?style=flat)
A Helm chart to deploy homarr for Kubernetes
@@ -259,7 +259,7 @@ httproute:
value: /
backendRefs:
- name: homarr
port: 8080
port: 7575
````
</details>
@@ -383,6 +383,7 @@ All available values are listed on the [artifacthub](https://artifacthub.io/pack
| containerPorts | object | `{"http":{"port":7575,"protocol":"TCP"}}` | containerPorts defines the ports to open on the container. It is a map where each entry specifies: - `port` (int) (required): The port number to expose inside the container. - `protocol` (string) (required): The network protocol (TCP or UDP) used for the port. - `disabled` (bool) : Optional flag to disable this port (defaults to false). Can be overridden via Helm values. By default, this configuration exposes TCP port 7575 with the name `http`. |
| database.migrationEnabled | bool | `true` | Database migration configuration. DB_MIGRATIONS_DISABLED Set to `true` to disable database migrations. Migrations are enabled by default (`false`). |
| database.type | string | `"sqlite"` | Database type: sqlite, mysql or postgresql |
| env.AUTH_COOKIE_PREFIX | string | `"homarr"` | Prefix used for all authentication cookies. Change if you run another Auth.js/NextAuth app on the same hostname to avoid cookie name collisions. Only letters, numbers, hyphens and underscores. |
| env.AUTH_LDAP_BASE | string | `nil` | Base dn of your LDAP server |
| env.AUTH_LDAP_BIND_DN | string | `nil` | User used for finding users and groups |
| env.AUTH_LDAP_GROUP_CLASS | string | `"groupOfUniqueNames"` | Class used for querying groups |
@@ -395,7 +396,6 @@ All available values are listed on the [artifacthub](https://artifacthub.io/pack
| env.AUTH_LDAP_USERNAME_FILTER_EXTRA_ARG | string | `nil` | Extra arguments for user search filter (& based) |
| env.AUTH_LDAP_USER_MAIL_ATTRIBUTE | string | `"mail"` | Attribute used for mail field |
| env.AUTH_LOGOUT_REDIRECT_URL | string | `nil` | URL to redirect to after clicking logging out. |
| env.AUTH_COOKIE_PREFIX | string | `"homarr"` | Prefix used for all authentication cookies. Change if you run another Auth.js/NextAuth app on the same hostname to avoid cookie name collisions. Only letters, numbers, hyphens and underscores. |
| env.AUTH_OIDC_AUTO_LOGIN | string | `"false"` | Automatically redirect to OIDC login |
| env.AUTH_OIDC_CLIENT_NAME | string | `"OIDC"` | Display name of provider (in login screen) |
| env.AUTH_OIDC_GROUPS_ATTRIBUTE | string | `"groups"` | Attribute used for groups (roles) claim |
@@ -419,17 +419,17 @@ All available values are listed on the [artifacthub](https://artifacthub.io/pack
| envSecrets.dbEncryption.key | string | `"db-encryption-key"` | Secret key for SECRET_ENCRYPTION_KEY can be generated with `openssl rand -hex 32` |
| fullnameOverride | string | `""` | Overrides chart's fullname |
| hostAliases | list | `[]` | Add static entries to /etc/hosts in the Pod. This is useful in the following cases: - You are running in a dual-stack cluster (IPv4 + IPv6) and want to force usage of IPv4 for specific hostnames - Your application is having DNS resolution issues or IPv6 preference issues - You need to override or simulate DNS entries without changing global DNS - You are running in an air-gapped or isolated environment without external DNS Example: hostAliases: - ip: "192.168.1.10" hostnames: - "example.com" - "example.internal" |
| httproute | object | `{"enabled":false,"hostnames":["chart-example.local"],"parentRefs":[{"name":"my-gateway","namespace":"default"}],"rules":[{"backendRefs":[{"name":"homarr","port":8080}],"filters":[],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]}` | Gateway API HTTPRoute configuration |
| httproute | object | `{"enabled":false,"hostnames":["chart-example.local"],"parentRefs":[{"name":"my-gateway","namespace":"default"}],"rules":[{"backendRefs":[{"name":"homarr","port":7575}],"filters":[],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]}` | Gateway API HTTPRoute configuration |
| httproute.enabled | bool | `false` | Enable HTTPRoute |
| httproute.hostnames | list | `["chart-example.local"]` | Hostnames this route matches (similar to ingress.hosts.host) |
| httproute.parentRefs | list | `[{"name":"my-gateway","namespace":"default"}]` | References to the parent Gateway(s) this route attaches to. Each item must include at least a `name`, and optionally a `namespace`. |
| httproute.rules | list | `[{"backendRefs":[{"name":"homarr","port":8080}],"filters":[],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]` | List of routing rules. Each rule can include: - matches: path/header/query matching - filters: optional transformations (redirects, header modifications, etc.) - backendRefs: one or more Kubernetes Services to forward traffic to |
| httproute.rules | list | `[{"backendRefs":[{"name":"homarr","port":7575}],"filters":[],"matches":[{"path":{"type":"PathPrefix","value":"/"}}]}]` | List of routing rules. Each rule can include: - matches: path/header/query matching - filters: optional transformations (redirects, header modifications, etc.) - backendRefs: one or more Kubernetes Services to forward traffic to |
| httproute.rules[0].filters | list | `[]` | Optional filters for this rule (default: empty) |
| httproute.rules[0].matches[0].path.type | string | `"PathPrefix"` | Path match type. One of: Exact, PathPrefix, RegularExpression |
| httproute.rules[0].matches[0].path.value | string | `"/"` | Path value to match |
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
| image.repository | string | `"ghcr.io/homarr-labs/homarr"` | Image repository |
| image.tag | string | `"v1.60.0"` | Overrides the image tag whose default is the chart appVersion |
| image.tag | string | `"v1.76.1"` | Overrides the image tag whose default is the chart appVersion |
| imagePullSecrets | list | `[]` | Secrets for Docker registry |
| ingress.annotations | object | `{}` | Ingress annotations |
| ingress.enabled | bool | `false` | Enable ingress |
@@ -0,0 +1,35 @@
---
title: "ArchiveTeam Warrior"
description: "ArchiveTeam Warrior is an easy-to-run virtual machine that helps preserve websites by using some of your bandwidth and disk space to download and upload content to ArchiveTeam’s archive."
hide_title: true
---
import { IntegrationHeader } from "@site/src/components/integrations/header";
import { AddingIntegration } from "@site/src/components/integrations/adding";
import { IntegrationSecrets } from "@site/src/components/integrations/secrets";
import { archiveTeamWarriorIntegration } from ".";
<IntegrationHeader integration={archiveTeamWarriorIntegration} categories={["archiving"]} />
The ArchiveTeam Warrior integration lets Homarr connect to your ArchiveTeam Warrior instance so you can manage and monitor your archiving tasks directly from your dashboard.
### Adding the integration
<AddingIntegration />
### Secrets
ArchiveTeam Warrior does not require authentication by default. If your instance is protected with basic authentication, you can provide a username and password.
<IntegrationSecrets
secrets={[
{
credentials: [],
steps: [],
},
{
credentials: ["username", "password"],
steps: [],
},
]}
/>
@@ -0,0 +1,9 @@
import { IntegrationDefinition } from "@site/src/types";
export const archiveTeamWarriorIntegration: IntegrationDefinition = {
name: "ArchiveTeam Warrior",
description:
"ArchiveTeam Warrior is an easy-to-run virtual machine that helps preserve websites by using some of your bandwidth and disk space to download and upload content to ArchiveTeam’s archive.",
iconUrl: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/archiveteam-warrior.png",
path: "../../integrations/archiveteam-warrior",
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

@@ -0,0 +1,54 @@
---
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';
<IntegrationHeader
integration={bazarrIntegration}
categories={['Subtitles', 'Media']}
/>
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';
<div className="flex flex-col gap-4">
<div>
<p>API key location in Bazarr (<strong>Settings → General → Security</strong>):</p>
<img src={apiKeySettings} alt="bazarr-api-key-settings" width={128 * 4} />
</div>
<div>
<p>Bazarr widget on a Homarr board:</p>
<img src={widgetOverview} alt="bazarr-widget-on-board" width={128 * 4} />
</div>
</div>
### Widgets & Capabilities
<IntegrationCapabilites
items={[{ widget: bazarrWidget }]}
/>
### Adding the integration
<AddingIntegration />
### Secrets
You can find your Bazarr API key under **Settings → General → Security**.
<IntegrationSecrets secrets={[{
credentials: ['apiKey'],
steps: [
"Open Bazarr and go to Settings → General → Security.",
"Copy the API key and paste it into Homarr when creating the integration.",
],
}]} />
@@ -0,0 +1,9 @@
import { IntegrationDefinition } from "@site/src/types";
export const bazarrIntegration: IntegrationDefinition = {
name: "Bazarr",
description:
"Bazarr is a companion application to Sonarr and Radarr that manages and downloads subtitles for your media library.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/bazarr.svg",
path: "../../integrations/bazarr",
};
@@ -1,37 +0,0 @@
---
title: 'Codeberg'
description: "Codeberg is a non-profit, community-driven platform for hosting and collaborating on software projects."
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 { codebergIntegration } from '.';
import { releasesWidget } from '@site/docs/widgets/releases';
<IntegrationHeader
integration={codebergIntegration}
categories={['Version Control', 'Software']}
/>
### Widgets & Capabilities
<IntegrationCapabilites
items={[{
widget: releasesWidget
}]}
/>
### Adding the integration
<AddingIntegration />
### Secrets
<IntegrationSecrets secrets={[{
credentials: [],
steps: []
}, {
credentials: ['personalAccessToken'],
steps: []
}]} />
@@ -1,9 +0,0 @@
import { IntegrationDefinition } from "@site/src/types";
export const codebergIntegration: IntegrationDefinition = {
name: "Codeberg",
description:
"Codeberg is a non-profit, community-driven platform for hosting and collaborating on software projects.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/codeberg.svg",
path: "../../integrations/codeberg",
};
@@ -1,37 +0,0 @@
---
title: 'Docker Hub'
description: "Docker Hub is a cloud-based registry service for sharing and managing Docker images."
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 { dockerHubIntegration } from '.';
import { releasesWidget } from '@site/docs/widgets/releases';
<IntegrationHeader
integration={dockerHubIntegration}
categories={['Container Management', 'Software']}
/>
### Widgets & Capabilities
<IntegrationCapabilites
items={[{
widget: releasesWidget
}]}
/>
### Adding the integration
<AddingIntegration />
### Secrets
<IntegrationSecrets secrets={[{
credentials: [],
steps: []
}, {
credentials: ['username', 'personalAccessToken'],
steps: []
}]} />
@@ -1,8 +0,0 @@
import { IntegrationDefinition } from "@site/src/types";
export const dockerHubIntegration: IntegrationDefinition = {
name: "Docker Hub",
description: "Docker Hub is a cloud-based registry service for sharing and managing Docker images.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/docker.svg",
path: "../../integrations/docker-hub",
};
@@ -55,6 +55,74 @@ services:
With docker run, add this parameter: `-v /var/run/docker.sock:/var/run/docker.sock`.
In Windows, you'll need to adjust the slashes: `-v //var/run/docker.sock:/var/run/docker.sock`
### Using Podman
On Linux, Homarr can connect to Podman's [Docker-compatible API](https://docs.podman.io/en/latest/markdown/podman-system-service.1.html).
The Podman API socket must be running and mounted into the Homarr container.
The socket grants full access to Podman, including arbitrary code execution as the user running the API, so only mount it into trusted containers.
For rootless Podman, enable the socket for the user that runs Homarr:
```bash
systemctl --user enable --now podman.socket
```
The rootless socket is located at `$XDG_RUNTIME_DIR/podman/podman.sock` (usually `/run/user/<uid>/podman/podman.sock`).
You can confirm the path with:
```bash
podman info --format '{{.Host.RemoteSocket.Path}}'
```
Mount that socket into the Homarr container and point `DOCKER_SOCKET_PATHS` to its path **inside** the container:
```yaml
services:
homarr:
container_name: homarr
image: ghcr.io/homarr-labs/homarr:latest
restart: unless-stopped
volumes:
- ${XDG_RUNTIME_DIR}/podman/podman.sock:/var/run/podman.sock
- ./homarr/appdata:/appdata
environment:
SECRET_ENCRYPTION_KEY: your_64_character_hex_string
DOCKER_SOCKET_PATHS: /var/run/podman.sock
ports:
- "7575:7575"
```
Start Homarr with `podman compose up -d`.
Run the compose project as the same user that owns the rootless Podman socket so `$XDG_RUNTIME_DIR` resolves to the correct path.
To keep the user socket available after logout and across reboots, enable lingering with `loginctl enable-linger <user>`.
For rootful Podman, enable the system socket with `sudo systemctl enable --now podman.socket`.
Its default path is `/run/podman/podman.sock`; mount that path instead and start Homarr with `sudo podman compose up -d`.
:::note SELinux
On systems with SELinux enabled, Podman's documentation recommends disabling label separation for a container that accesses the API socket.
Add the following to the Homarr service:
```yaml
security_opt:
- label=disable
```
:::
You can connect Homarr to multiple Docker-compatible sockets by mounting each socket and listing their in-container paths, separated by commas:
```yaml
services:
homarr:
image: ghcr.io/homarr-labs/homarr:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ${XDG_RUNTIME_DIR}/podman/podman.sock:/var/run/podman.sock
environment:
DOCKER_SOCKET_PATHS: /var/run/docker.sock,/var/run/podman.sock
```
### 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:
@@ -1,42 +0,0 @@
---
title: 'GitHub Container Registry'
description: "GitHub Container Registry is a platform for hosting and managing packages."
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 { gitHubContainerRegistryIntegration } from '.';
import { releasesWidget } from '@site/docs/widgets/releases';
<IntegrationHeader
integration={gitHubContainerRegistryIntegration}
categories={['Package Management', 'Software']}
/>
### Widgets & Capabilities
<IntegrationCapabilites
items={[{
widget: releasesWidget
}]}
/>
### Adding the integration
<AddingIntegration />
### Secrets
<IntegrationSecrets secrets={[{
credentials: [],
steps: []
}, {
credentials: ["personalAccessToken"],
steps: []
}, {
tabLabel: "GitHub App",
credentials: ['githubAppId', 'githubInstallationId', 'privateKey'],
steps: ['Create GitHub App', 'Create a private key for it', 'Install it to your organization / user']
}]} />
@@ -1,11 +0,0 @@
import { IntegrationDefinition } from "@site/src/types";
export const gitHubContainerRegistryIntegration: IntegrationDefinition = {
name: "GitHub Container Registry",
description: "GitHub Container Registry is a platform for hosting and managing packages.",
iconUrl: {
light: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/github.svg",
dark: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/github-light.svg",
},
path: "../../integrations/github-packages",
};
@@ -1,41 +0,0 @@
---
title: 'GitHub'
description: "GitHub is a web-based platform for version control and collaboration."
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 { githubIntegration } from '.';
import { releasesWidget } from '@site/docs/widgets/releases';
<IntegrationHeader
integration={githubIntegration}
categories={['Version Control', 'Software']}
/>
### Widgets & Capabilities
<IntegrationCapabilites
items={[{
widget: releasesWidget
}]}
/>
### Adding the integration
<AddingIntegration />
### Secrets
<IntegrationSecrets secrets={[{
credentials: [],
steps: []
}, {
credentials: ['personalAccessToken'],
steps: []
}, {
tabLabel: "GitHub App",
credentials: ['githubAppId', 'githubInstallationId', 'privateKey'],
steps: ['Create GitHub App', 'Create a private key for it', 'Install it to your organization / user']
}]} />
@@ -1,11 +0,0 @@
import { IntegrationDefinition } from "@site/src/types";
export const githubIntegration: IntegrationDefinition = {
name: "GitHub",
description: "GitHub is a web-based platform for version control and collaboration.",
iconUrl: {
light: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/github.svg",
dark: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/github-light.svg",
},
path: "../../integrations/github",
};
@@ -1,37 +0,0 @@
---
title: 'GitLab'
description: "GitLab is a web-based DevOps lifecycle tool that provides a Git repository manager."
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 { gitlabIntegration } from '.';
import { releasesWidget } from '@site/docs/widgets/releases';
<IntegrationHeader
integration={gitlabIntegration}
categories={['Version Control', 'Software']}
/>
### Widgets & Capabilities
<IntegrationCapabilites
items={[{
widget: releasesWidget
}]}
/>
### Adding the integration
<AddingIntegration />
### Secrets
<IntegrationSecrets secrets={[{
credentials: [],
steps: []
}, {
credentials: ['personalAccessToken'],
steps: []
}]} />
@@ -1,8 +0,0 @@
import { IntegrationDefinition } from "@site/src/types";
export const gitlabIntegration: IntegrationDefinition = {
name: "GitLab",
description: "GitLab is a web-based DevOps lifecycle tool that provides a Git repository manager.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/gitlab.svg",
path: "../../integrations/gitlab",
};
@@ -0,0 +1,52 @@
---
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';
<IntegrationHeader
integration={gluetunIntegration}
categories={['VPN', 'Network']}
/>
[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.
### Widgets & Capabilities
<IntegrationCapabilites
items={[{
widget: vpnWidget,
}]}
/>
### Setting up the Gluetun control server
Refer to the [Gluetun control server documentation](https://github.com/qdm12/gluetun-wiki/blob/main/setup/advanced/control-server.md#authentication) to enable and configure authentication.
### Adding the integration
<AddingIntegration />
### Secrets
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.
<IntegrationSecrets secrets={[{
credentials: [],
steps: [],
},{
credentials: ['username', 'password'],
steps: [],
},{
credentials: ['apiKey'],
steps: [],
},,]} />
@@ -0,0 +1,8 @@
import { IntegrationDefinition } from "@site/src/types";
export const gluetunIntegration: IntegrationDefinition = {
name: "Gluetun",
description: "VPN control server integration for Homarr's VPN widget.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/gluetun.svg",
path: "../../integrations/gluetun",
};
+20 -8
View File
@@ -39,13 +39,25 @@ import { immichServerStatsWidget } from '../../widgets/immich-server-stats';
'Scroll down to "API Keys"',
'Click "New API Key"',
'Enter a name, e.g. "Homarr"',
(<span>
Select the following permissions:{" "}
<code>album.read</code>,{" "}
<code>user.read</code>,{" "}
<code>server.statistics</code>,{" "}
<code>asset.download</code>
</span>),
(
<span>
Select the following permissions:{" "}
<code>album.statistics</code>,{" "}
<code>album.read</code>,{" "}
<code>album.create</code>,{" "}
<code>user.read</code>,{" "}
<code>user.update</code>,{" "}
<code>asset.read</code>,{" "}
<code>asset.view</code>,{" "}
<code>asset.download</code>,{" "}
<code>asset.statistics</code>,{" "}
<code>server.statistics</code>,{" "}
<code>server.about</code>.
</span>
),
'Create the integration in Homarr and copy the API key to there'
]
}]} />
}]} />
@@ -1,34 +0,0 @@
---
title: 'LinuxServer.io'
description: "LinuxServer.io is a platform for managing and deploying containerized applications."
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 { linuxServerIoIntegration } from '.';
import { releasesWidget } from '@site/docs/widgets/releases';
<IntegrationHeader
integration={linuxServerIoIntegration}
categories={['Container Management', 'Software']}
/>
### Widgets & Capabilities
<IntegrationCapabilites
items={[{
widget: releasesWidget
}]}
/>
### Adding the integration
<AddingIntegration />
### Secrets
<IntegrationSecrets secrets={[{
credentials: [],
steps: []
}]} />
@@ -1,8 +0,0 @@
import { IntegrationDefinition } from "@site/src/types";
export const linuxServerIoIntegration: IntegrationDefinition = {
name: "LinuxServer.io",
description: "LinuxServer.io is a platform for managing and deploying containerized applications.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/linuxserver-io.svg",
path: "../../integrations/linux-server-io",
};
@@ -10,19 +10,21 @@ import { AddingIntegration } from '@site/src/components/integrations/adding';
import { IntegrationSecrets } from '@site/src/components/integrations/secrets';
import { navidromeIntegration } from '.';
import { audioStatsWidget } from '@site/docs/widgets/audio-stats';
import { mediaServerWidget } from '@site/docs/widgets/media-server';
<IntegrationHeader
integration={navidromeIntegration}
categories={['Media']}
categories={['Media', 'Media server']}
/>
Navidrome provides music library statistics including artist, album, and song counts, as well as now playing information via the Subsonic API.
Navidrome provides music library statistics including artist, album, and song counts, as well as now playing audio streams via the Subsonic API.
### Widgets & Capabilities
<IntegrationCapabilites
items={[
{ widget: audioStatsWidget },
{ widget: mediaServerWidget },
]}
/>
-34
View File
@@ -1,34 +0,0 @@
---
title: 'NPM'
description: "NPM is a package manager for the JavaScript programming language, primarily used for managing Node.js packages."
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 { npmIntegration } from '.';
import { releasesWidget } from '@site/docs/widgets/releases';
<IntegrationHeader
integration={npmIntegration}
categories={['Package Management', 'Software']}
/>
### Widgets & Capabilities
<IntegrationCapabilites
items={[{
widget: releasesWidget
}]}
/>
### Adding the integration
<AddingIntegration />
### Secrets
<IntegrationSecrets secrets={[{
credentials: [],
steps: []
}]} />
-9
View File
@@ -1,9 +0,0 @@
import { IntegrationDefinition } from "@site/src/types";
export const npmIntegration: IntegrationDefinition = {
name: "NPM",
description:
"NPM is a package manager for the JavaScript programming language, primarily used for managing Node.js packages.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/npm.svg",
path: "../../integrations/npm",
};
@@ -0,0 +1,43 @@
---
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';
<IntegrationHeader
integration={patchmonIntegration}
categories={['Health Monitoring']}
/>
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
<IntegrationCapabilites
items={[
{ widget: patchmonWidget },
]}
/>
### Adding the integration
<AddingIntegration />
### Secrets
<IntegrationSecrets secrets={[{
credentials: ['patchmonApiKey', 'patchmonApiSecret'],
steps: [
'Open your PatchMon instance',
'Navigate to Settings and create a new GetHomepage API key',
'Copy the API key and secret from the success dialog',
'Paste them into Homarr — Basic authentication is handled automatically',
]
}]} />
@@ -0,0 +1,9 @@
import { IntegrationDefinition } from "@site/src/types";
export const patchmonIntegration: IntegrationDefinition = {
name: "PatchMon",
description:
"PatchMon is a patch management and monitoring solution for Linux hosts, tracking package updates and security patches across your infrastructure.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/patchmon.svg",
path: "../../integrations/patchmon",
};
@@ -1,37 +0,0 @@
---
title: 'Quay'
description: "Quay is a container registry for storing and managing container images."
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 { quayIntegration } from '.';
import { releasesWidget } from '@site/docs/widgets/releases';
<IntegrationHeader
integration={quayIntegration}
categories={['Container Registry', 'Software']}
/>
### Widgets & Capabilities
<IntegrationCapabilites
items={[{
widget: releasesWidget
}]}
/>
### Adding the integration
<AddingIntegration />
### Secrets
<IntegrationSecrets secrets={[{
credentials: [],
steps: []
}, {
credentials: ["personalAccessToken"],
steps: []
}]} />
@@ -1,8 +0,0 @@
import { IntegrationDefinition } from "@site/src/types";
export const quayIntegration: IntegrationDefinition = {
name: "Quay",
description: "Quay is a container registry for storing and managing container images.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/quay.png",
path: "../../integrations/quay",
};
@@ -1,28 +0,0 @@
---
title: 'Search.ch'
description: "Search.ch supports searching for timetables in Switzerland."
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 { IconDownload } from "@tabler/icons-react";
import { searchChIntegration } from '.';
import Alert from '@theme/Admonition';
import { timetableWidget } from '@site/docs/widgets/timetable';
<IntegrationHeader
integration={searchChIntegration}
categories={['Timetable']}
/>
### Widgets & Capabilities
<IntegrationCapabilites
items={[{ widget: timetableWidget }]}
/>
### Adding the integration
<AddingIntegration />
@@ -1,7 +0,0 @@
import { IntegrationDefinition } from "@site/src/types";
export const searchChIntegration: IntegrationDefinition = {
name: "Search.ch",
description: "Search.ch supports searching for timetables in Switzerland.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/search-ch.png",
path: "../../integrations/search-ch",
};
@@ -0,0 +1,96 @@
---
title: "Synology DiskStation"
description: "Monitor CPU, memory, storage volumes, and system health from Synology DSM."
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 { synologyIntegration } from ".";
import { systemResourcesWidget } from "@site/docs/widgets/system-resources";
import { systemDisksWidget } from "@site/docs/widgets/system-disks";
import { healthMonitoringWidget } from "@site/docs/widgets/health-monitoring";
import Alert from "@theme/Admonition";
<IntegrationHeader integration={synologyIntegration} categories={["NAS", "Hardware"]} />
### Widgets & Capabilities
<IntegrationCapabilites
items={[
{ widget: healthMonitoringWidget },
{ widget: systemResourcesWidget },
{ widget: systemDisksWidget },
]}
/>
### Supported metrics
| Widget section | DSM API source | May be unavailable |
| ---------------------------- | ----------------------------------------------------- | ------------------------------------------------------- |
| CPU ring / chart | `SYNO.Core.System.Utilization` | — |
| Memory ring / chart | `SYNO.Core.System.Utilization` | — |
| CPU temperature ring | `SYNO.Core.System` system info | Models without a temperature sensor |
| Network charts | `SYNO.Core.System.Utilization` network totals | Some DSM builds or permission configurations |
| Load average (info modal) | `SYNO.Core.System.Utilization` CPU load fields | — |
| Storage volume usage | `SYNO.Core.System` storage info / Storage Manager API | — |
| SMART status and temperature | Storage Manager and SMART APIs | Disk-to-volume mapping may be incomplete on some setups |
| Reboot / update indicator | `SYNO.Core.System.Status` / upgrade APIs | Permission-dependent |
| GPU | Not available | Typical DiskStation models |
### Adding the integration
<AddingIntegration />
<Alert type="info" title="Use the correct DSM URL">
Enter the HTTP or HTTPS URL of your Synology DSM web interface, for example <code>http://diskstation.local:5000</code>{" "}
or <code>https://diskstation.local:5001</code>. If DSM uses a self-signed certificate, add it under{" "}
<a href="/docs/management/certificates">Management &gt; Tools &gt; Certificates</a> so Homarr can connect securely.
</Alert>
### Secrets
<IntegrationSecrets
secrets={[
{
credentials: ["username", "password"],
steps: [
"Create a dedicated DSM user with a strong password for Homarr.",
"Add the user to the default Administrators group so Homarr can read `SYNO.Core.System` metrics.",
"Under User Groups and Permissions, deny access to shared folders and most applications.",
"Allow login to DSM only, optionally restricted by source IP address.",
"Log in once with the service account in DSM to accept terms and conditions.",
],
body: (
<>
<Alert type="caution" title="Administrators group required">
Homarr reads system, storage, and utilization data from APIs that require membership in the default
Administrators group.
</Alert>
<Alert type="warning" title="Two-factor authentication is not supported">
Accounts with 2-step verification enabled cannot authenticate with this integration. Use a dedicated service
account without 2FA.
</Alert>
<Alert type="tip" title="First-time setup">
If login fails during testing, temporarily disable automatic blocking for invalid logins under Control Panel
&gt; Security &gt; Protection, then re-enable it after Homarr connects successfully.
</Alert>
</>
),
},
]}
/>
### Storage volume selection
Health Monitoring and System Disks widgets can filter Synology storage volumes when **every** selected integration is a Synology DiskStation. Leave **Visible storage volumes** empty to show all volumes, or pick specific volumes from the list. When multiple Synology integrations are connected, volumes are labeled with the integration name.
<Alert type="note" title="Synology-only option">
The volume filter is hidden when the widget also uses non-Synology integrations such as TrueNAS or Unraid.
</Alert>
<Alert type="note" title="Volume ordering">
When no volume filter is configured, the first volume returned by DSM is not guaranteed to be `volume_1`.
</Alert>
@@ -0,0 +1,8 @@
import { IntegrationDefinition } from "@site/src/types";
export const synologyIntegration: IntegrationDefinition = {
name: "Synology DiskStation",
description: "Monitor CPU, memory, storage volumes, and system health from Synology DSM.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/synology.svg",
path: "../../integrations/synology",
};
@@ -0,0 +1,57 @@
---
title: "Traefik"
description: "Cloud-native reverse proxy and load balancer"
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 { traefikIntegration } from ".";
import { traefikWidget } from "../../widgets/traefik";
<IntegrationHeader integration={traefikIntegration} categories={["Reverse proxy", "Monitoring"]} />
### Widgets & Capabilities
<IntegrationCapabilites items={[{ widget: traefikWidget }]} />
### Adding the integration
<AddingIntegration />
:::info URL configuration
Use the URL where Traefik exposes its dashboard/API, for example `http://traefik:8080` or `https://traefik.example.com`. Homarr calls Traefik endpoints under `/api` automatically.
:::
:::warning API requirement
Traefik must have the API enabled. For local or internal setups this is commonly exposed through `api.insecure=true`; for production setups, expose the `api@internal` service through an authenticated router.
:::
### Secrets
<IntegrationSecrets
secrets={[
{
credentials: [],
steps: [
"Choose this option when the Traefik API is only reachable from a trusted internal network and does not require authentication.",
],
},
{
credentials: ["username", "password"],
steps: [
"Use this option when your Traefik dashboard route is protected by Basic Auth.",
"Enter the same username and password required to open the Traefik dashboard.",
],
},
{
credentials: ["apiKey"],
steps: [
"Use this option when your Traefik dashboard route accepts a bearer token.",
"Paste the token into the API Key field in Homarr.",
],
},
]}
/>
@@ -0,0 +1,8 @@
import { IntegrationDefinition } from "@site/src/types";
export const traefikIntegration: IntegrationDefinition = {
name: "Traefik",
description: "Cloud-native reverse proxy and load balancer",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/traefik.svg",
path: "../../integrations/traefik",
};
@@ -27,6 +27,8 @@ import Alert from '@theme/Admonition';
]}
/>
The storage values shown by these widgets come from each pool's root ZFS dataset, so they already account for RAIDZ parity overhead and dataset limits and match what `zfs list` and the TrueNAS web interface report. When a pool cannot report its dataset space, Homarr falls back to the pool's physical values, which read higher on RAIDZ.
### Adding the integration
<AddingIntegration />
@@ -0,0 +1,48 @@
---
title: "What's Up Docker"
description: "What's Up Docker (WUD) watches your Docker containers and reports which ones have newer image versions available."
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 { wudIntegration } from ".";
import { wudWidget } from "@site/docs/widgets/whats-up-docker";
<IntegrationHeader integration={wudIntegration} categories={["Health Monitoring"]} />
The What's Up Docker integration lets Homarr connect to your [WUD](https://github.com/getwud/wud) instance so you can see how many of your watched containers have image updates available directly from your dashboard.
### Widgets & Capabilities
<IntegrationCapabilites items={[{ widget: wudWidget }]} />
### Adding the integration
<AddingIntegration />
:::info URL configuration
Use the root URL of your WUD instance, for example `https://wud.example.com`. Homarr calls the `/api/app` and `/api/containers` endpoints under that URL automatically.
:::
### Secrets
WUD does not require authentication by default. If your instance is protected with [Basic Authentication](https://github.com/getwud/wud/blob/main/docs/configuration/authentications/basic/README.md), you can provide a username and password.
<IntegrationSecrets
secrets={[
{
credentials: [],
steps: [],
},
{
credentials: ["username", "password"],
steps: [
"Open your WUD instance's configuration and configure a WUD_AUTH_BASIC_* user as described in the WUD documentation",
"Enter that username and password in Homarr — Basic authentication is handled automatically",
],
},
]}
/>
@@ -0,0 +1,9 @@
import { IntegrationDefinition } from "@site/src/types";
export const wudIntegration: IntegrationDefinition = {
name: "What's Up Docker",
description:
"What's Up Docker (WUD) watches your Docker containers and reports which ones have newer image versions available.",
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/whats-up-docker.svg",
path: "../../integrations/whats-up-docker",
};
+13 -1
View File
@@ -70,4 +70,16 @@ API key authentication enables programmatic access for:
- Automation scripts and CI/CD pipelines
- Third-party integrations
- Custom dashboards and monitoring tools
- Container orchestration systems that need to sync app definitions
- Container orchestration systems that need to sync app definitions
## Board Automation
The OpenAPI and MCP APIs include board management endpoints for common automation workflows:
- Create, duplicate, rename and delete boards
- Change board visibility
- Update board visual and behavior settings
- Set desktop and mobile home boards for the current user
- Configure global board defaults such as public home boards and status behavior
Use the interactive API reference to inspect the exact request body for each endpoint under the `boards` and `settings` tags.
+9 -6
View File
@@ -7,8 +7,8 @@ tags:
- Ping
---
Apps are the building blocks of your Homarr board.
Most of the time they are a simple link to a website, but used on your board they also support a simple ping to check if your service is up.
Apps are the building blocks of your Homarr board.
Most of the time they are a simple link to a website, but used on your board they also support a simple ping to check if your service is up.
Apps are used in the bookmark and app widget.
## Create an app
@@ -27,8 +27,8 @@ The name must be at least one character long and can be chosen freely.
### Icon URL
This is the URL to the icon that will be displayed on the app widget.
It can be a url to an image in the internet, one from the included icon repositories or a local file uploaded through the upload button.
This is the URL to the icon that will be displayed on the app widget.
You can paste a direct HTTP(S) URL to an image, search the included icon repositories by name, or upload a local file through the upload button. The app name is pre-filled as the initial library search when no image is selected. Local images appear first, followed by SVG icons and other formats. Direct image URLs are previewed, used as entered, and are not searched in the icon repositories.
![Icon URL](./img/app-icon-url.png)
@@ -40,14 +40,17 @@ An optional description that can be shown as tooltip on the app widget.
The URL to the website you want to link to. Clicking on the app widget or bookmark will open this URL.
You can also use custom URI schemes such as `vscode://file/path`, `microsoft-edge:https://example.com`, or `myapp://open` to link to local applications or third-party programs. We trust that you know what you are doing — only `javascript:` URIs are blocked for security reasons.
### Ping URL
When you want to use another url for the simple status check you can set it here.
When you want to use another url for the simple status check you can set it here.
This will allow you to set a different URL for the ping than the URL that is opened when clicking on the app widget.
It's useful when you want to ping the service internally for example with a custom ip but open the website externally.
Note that the ping URL only accepts `http://` and `https://` URLs — custom URI schemes are not supported for pings.
## List of apps
On the apps management page you find all apps that exist in your Homarr instance. You can edit and delete them.
![Apps list](./img/app-list.png)
![Apps list](./img/app-list.png)
+70 -33
View File
@@ -9,11 +9,11 @@ tags:
- Layout
---
import iconColorImage from './img/icon-color.png'
import itemRadiusImage from './img/item-radius.png'
import layoutLargeImage from './img/layout-large.png'
import layoutMediumImage from './img/layout-medium.png'
import layoutSmallImage from './img/layout-small.png'
import iconColorImage from "./img/icon-color.png";
import itemRadiusImage from "./img/item-radius.png";
import layoutLargeImage from "./img/layout-large.png";
import layoutMediumImage from "./img/layout-medium.png";
import layoutSmallImage from "./img/layout-small.png";
Each dashboard is called a "board".
You can create as many boards as you want.
@@ -24,24 +24,29 @@ Other boards can be viewed by direct links (e.g. my-homarr.com/board/smart-home)
Names of boards must be unique because this will be used in the URL to load the desired board.
## Create a new board
When creating a board, the availability of the board name will be checked for you.
![](./img/create-board-modal.png)
### Name
The name must not include any special characters and must be at least one character long.
Underscores and hyphen-minus are allowed.
### Column count
Homarr has a complex drag and drop system that can be used from the browser.
Homarr has a complex drag-and-drop system that can be used from the browser.
The column count defines how many horizontal columns are available to drag and drop elements to.
### Public
This will enable public access for everyone - regardless of whether they are logged in or not.
This can be really useful if you want to have public boards in your company or for family and fiends.
This can be really useful if you want to have public boards in your company or for family and friends.
Modifications for public boards must be allowed explicitly using user groups and their permissions.
## Board settings
You navigate to the board settings by clicking on these three dots:
![](./img/navigate-to-settings.png)
@@ -50,8 +55,12 @@ Alternatively, you can also navigate from the board page itself using the cog ic
![](./img/navigate-to-settings-2.png)
All board settings are edited on a single page. Click the **Save changes** button in the save bar at the bottom to apply them, or **Discard** to restore the last saved values. The save bar only appears when you have unsaved changes. Access control and the Danger zone are independent sections and are applied immediately.
### General
#### Page title
This is the title that will be visible at the top left in the navigation bar:
![](./img/page-title.png)
@@ -59,6 +68,7 @@ This is the title that will be visible at the top left in the navigation bar:
This field is optional and Homarr will fall back to "Homarr" if nothing is set.
#### Meta title
This is the secondary title of the page that is not directly visible in the page itself.
Browser will use it to set the title of tabs:
@@ -67,10 +77,12 @@ Browser will use it to set the title of tabs:
Homarr will fall back to the board name and a suffix if nothing is set.
#### Logo image URL
This is the URL that is used for the image at the top left.
Homarr will fall back to the Homarr logo if nothing is set.
#### Favicon image URL
This is the URL that is used for the favicon in the tab title.
Homarr will fall back to the Homarr logo if nothing is set.
@@ -94,51 +106,65 @@ Amount of columns for this layout. Defines how many items can be placed in a row
#### Breakpoint
Minimum width of the screen where the layout will be used.
Once the minmum of the next layout is reached the layout will change.
Minimum width of the screen where the layout will be used.
Once the minimum of the next layout is reached the layout will change.
#### Preview
<img src={layoutSmallImage} height={256} />
<img src={layoutMediumImage} height={256} />
<img src={layoutLargeImage} height={256} />
<img src={layoutSmallImage} height={256} />
<img src={layoutMediumImage} height={256} />
<img src={layoutLargeImage} height={256} />
### Background
#### Background image URL
Homarr can display a background image behind apps and widgets.
This URL can be used to define what image should be shown.
#### Background image attachment
This defines whether the background should move when the user scrolls.
#### Background image size
This defines whether the background should cover the entire page (and possibly be cropped) or never be cropped but may not cover the entire page.
#### Background image repeat
This defines whether the background should be repeated if it cannot cover the entire page.
This option can be useful if you have patterns that can be repeated easily (e.g. patterns):
![](./img/background-repeat.png)
### Appearance
#### Primary color
Color that can be chosen freely to give accents to active elements.
#### Secondary color
Color that can be chosen freely to give accents.
#### Opacity
Opacity of the colors.
#### Icon color
Change the color of your bookmark / app icons.
<img src={iconColorImage} height={100} />
<img src={iconColorImage} height={100} />
#### Item radius
Change the radius of your items / categories.
<img src={itemRadiusImage} height={100} />
<img src={itemRadiusImage} height={100} />
### Custom CSS
This is the field where you can enter custom CSS.
The styling will only be applied on the respective board page.
@@ -147,14 +173,16 @@ The styling will only be applied on the respective board page.
### Behaviour
#### Disable app status
This will disable the status check for apps.
### Access control
With the access control, you can permit a single user or a group to your board.
The users and groups can have one of these three levels of access:
| **Permission Level** | View board | Edit mode | Settings | Danger zone (eg. delete) |
|----------------------|------------|-----------|----------|--------------------------|
| -------------------- | ---------- | --------- | -------- | ------------------------ |
| View board | X | | | |
| Modify board | X | X | X | |
| Full access | X | X | X | X |
@@ -173,22 +201,27 @@ After editing permissions, the save button below the table must be pressed.
Otherwise, all changes will be discarded.
### Danger zone
#### Rename
Renaming a board will break all existing links to it permanently with no redirect.
#### Board visibility
By default, boards will be private. This means only authenticated users that are authorized have access.
Making a board public will expose it to everyone - including unauthenticated users.
#### Delete
This will permanently delete the board.
This action is irreversible and cannot be undone.
## Delete boards
The deletion of boards is permanent and cannot be undone.
There are two ways to delete a board:
- Navigate to the settings of your board, open the "Danger zone" dropdown and click on the "delete this board" button.
- Navigate to the settings of your board, open the "Danger zone" section and click on the "delete this board" button.
- Navigate to the list of boards in the management pages, click the three dots and click on "delete permanently".
Both actions will execute the same deletion process.
@@ -196,7 +229,7 @@ Both actions will execute the same deletion process.
## Duplicate boards
:::note
Duplicating a board will not copy the users and groups that have access to the board
Duplicating a board will not copy the users and groups that have access to the board
nor the integrations the user does not have access to.
:::
@@ -206,47 +239,51 @@ You can duplicate a board by clicking on the three dots in the list of boards an
![](./img/duplicate-board-modal.png)
## Setting boards as your home board
The home board is the dashboard, that will be shown at the root path of Homarr or if no board name was passed in the URL.
All the following paths will lead to the home board:
- ``my-homarr.com``
- ``my-homarr.com/boards``
- `my-homarr.com`
- `my-homarr.com/boards`
Your home board will have a special small badge at the top right in the list of boards:
![](./img/home-board-flag.png)
### For yourself
To set the home board yourself, the easiest option is to set it directly in the list of boards:
![](./img/set-as-home-board-menu.png)
Alternatively, you can also define it via your user profile:
1. Click on your user profile at the top right
2. Click on ``Your preferences``
3. Change the home board in the ``home board`` dropdown and click on ``Save``.
2. Click on `Your preferences`
3. Change the home board in the `home board` dropdown and click on `Save`.
### For other users
1. Navigate to the users: ``Management`` > ``Users`` > ``Manage``
1. Navigate to the users: `Management` > `Users` > `Manage`
2. Click on the username of the user that you want to adjust
3. Select the desired home board via the dropdown and click on ``Save`` \
![](./img/set-home-board-other-user.png)
3. Select the desired home board via the dropdown and click on `Save` \
![](./img/set-home-board-other-user.png)
### For user groups
1. Navigate to the user groups: ``Management`` > ``Users`` > ``Groups`` > ``Manage``
2. Go to tab ``Settings``
3. Select the desired home board via the dropdown and click on ``Save`` \
![](./img/set-home-board-user-group.png)
1. Navigate to the user groups: `Management` > `Users` > `Groups` > `Manage`
2. Go to tab `Settings`
3. Select the desired home board via the dropdown and click on `Save` \
![](./img/set-home-board-user-group.png)
### For whole server
You can also set a global home board that will be used for all users that have not set a home board themselves.
It will also be used for anonymous users.
1. Navigate to the settings: ``Management`` > ``Settings`` > ``Boards``
2. Select the desired home board via the dropdown and click on ``Save`` \
![](./img/set-home-board-global.png)
1. Navigate to the settings: `Management` > `Settings` > `Boards`
2. Select the desired home board via the dropdown and click on `Save` \
![](./img/set-home-board-global.png)
:::note
For the global home board you can only select boards that are public.
@@ -255,4 +292,4 @@ For the global home board you can only select boards that are public.
### Mobile home board
Same as the home board, you can also set a mobile home board.
It will be used for devices that are detected as mobile devices. (Using User-Agent header)
It will be used for devices that are detected as mobile devices. (Using User-Agent header)
@@ -52,14 +52,21 @@ The certificates are stored in the `/appdata/trusted-certificates` directory whi
This means you can automate the update of the certificates by simply replacing or adding a new file in the directory.
## Obtaining certificates
Every integration has its own way of obtaining certificates.
Generally it is recommended to search for the documentation of the integration you are using.
Most of the time you can find the certificate in the file system of the integration.
The certificate file needs to be uploaded to Homarr. To first get the file on your computer you can either:
- use `scp user@host:/path/to/file ./certificate.pem`
- use `cat /path/to/file` to print the certificate. Then recreate the file on your machine.
Below you can find instructions for some of the integrations.
### Pi-hole (v6)
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/).
The certificate can be found in the path `/etc/pihole/tls_ca.crt`.
You can find more details regarding SSL / TLS for Pi-hole [here](https://docs.pi-hole.net/api/tls/).
### Proxmox
By default, Proxmox VE uses a node certificate signed by the cluster. You only need to configure Homarr with the certificate of a single node.
The certificate can be found in any node on the path `/etc/pve/pve-root-ca.pem`.
You can learn more about certificate management in Proxmox [here](https://pve.proxmox.com/wiki/Certificate_Management).
+1
View File
@@ -141,6 +141,7 @@ Homarr exposes 50+ tools organized by namespace. Each tool is either a **query**
| `dnsHole` | DNS hole summary, toggle blocking | GET + POST |
| `downloads` | Active downloads, pause/resume/delete | GET + POST |
| `healthMonitoring` | Resource usage stats | GET |
| `patchmon` | Host patch and security update statistics | GET |
| `mediaRequests` | Approve/decline media requests | GET + POST |
| `mediaServer` | Media server sessions and stats | GET |
| `smartHome` | Execute automations, device states | GET + POST |
+83 -53
View File
@@ -9,97 +9,127 @@ tags:
---
# Settings
The settings page has a few options that will be applied to the entire Homarr application.
They may require a full page reload for changes to apply.
The settings page applies options to the whole Homarr application.
Some changes need a full page reload before they take effect.
All changes are collected in a single form. Click the **Save changes** button in the save bar at the bottom of the page to apply them. The save bar only appears when you have unsaved changes, and the **Discard** button reverts your changes.
## Analytics
By default, Homarr is collecting anonymous analytics to identify issues and prioritize bugfixes and improvements.
The data is never shared with any third-parties and is fully GDPR & CCPA compliant.
The software being used is [Umami Analytics](https://umami.is/) which is fully open source.
The main server software can be found [here](https://github.com/umami-software/umami) and [this node library](https://github.com/umami-software/node) to perform server side calls to the API.
A full list of the collected data by default can be found here: https://umami.is/docs/metric-definitions.
Homarr uses [PostHog](https://posthog.com/) to collect anonymous usage data.
We collect this data to see what features people ACTUALLY use.
We use this data to decide where we spend our development time.
We understand that you might not want Homarr to communicate with our services.
By unchecking the ``Send anonymous analytics`` checkbox and reloading the full page, all communication by Umami will be disabled and no data will be collected.
If you are paranoid, you can permanently block ``umami.homarr.dev`` from your DNS / firewall.
We do not sell the data. We do not share the data with third parties.
The data does not contain personal information and does not identify you or your installation.
Additionally, you opt in to more data collection to help us provide more useful data.
Homarr sends the data to our own PostHog server at `https://hog.homarr.dev`.
The server sends the data once a week and when the server starts.
### Integration data
Enabling this optional data will send the types of integrations (e.g. SABnzbd, Sonarr, ...) and how many you have configured of them.
This will not include any URLs, names, secrets, errors and others. This is disabled by default.
### What we collect
### Widget data
Enabling this optional data will send the types of widgets (e.g. downloads, media streams, iframe, ...) and how many you have configured of them.
This will not include any URLs, names, secrets, errors and others. This is disabled by default.
Homarr collects technical data about your installation:
### Users data
Enabling this optional data will send the count of users and whether you activated SSO.
This will not include any usernames, passwords, emails, URLs, authentication flows or client IDs.
This is disabled by default.
- Your Homarr version
- Your database type (SQLite, MySQL, or PostgreSQL)
- Whether Docker or Kubernetes is enabled
- Your enabled authentication providers
- Your operating system and CPU architecture
- Your default language
- The number of boards, apps, sections, layouts, users, groups, search engines, icon repositories, cron jobs, API keys, invites, sessions, and accounts
- The integration types you use and how many you have of each (for example, Sonarr or SABnzbd)
- The widget types you use and how many you have of each
Homarr does NOT collect:
- URLs
- Names
- Usernames, emails, or passwords
- Integration secrets or API keys
- Error messages or logs
- Any data that can identify you
Each installation gets a random ID. We use this ID only to count unique installations. We cannot use this ID to identify you.
Homarr does not use cookies for analytics. Homarr does not track page views automatically. Homarr only sends the data listed above.
### Disable analytics
Analytics are enabled by default. To disable analytics:
1. Open the Settings page.
2. Uncheck the "Help us improve Homarr" checkbox.
3. Reload the full page.
When analytics are disabled, Homarr does not send any data to PostHog.
You can also set the `NO_EXTERNAL_CONNECTION` environment variable to `true`. This stops all external requests, including analytics. See the [environment variables](/docs/advanced/environment-variables) page for more information.
You can block `hog.homarr.dev` in your DNS or firewall. Homarr cannot send data when this address is blocked.
## Search Engine Optimization (SEO)
Big companies [like Google, Microsoft, Baidu and Yandex](https://de.wikipedia.org/wiki/Web-Index) will use [web crawlers](https://de.wikipedia.org/wiki/Webcrawler) to index the Internet for new websites & pages.
This is desirable in many cases (for example when selling products in an online shop) but can lead to unwanted traffic and attention to your personal dashboard.
Homarr is requesting the crawlers to not index Homarr instances by default for this reason.
If you use Homarr as a public website and want it to be searchable on these search engines, you can disable these settings.
Please note that Homarr doesn't have control over what the crawlers do; it is a mere request to them to not perform these actions but will not guarantee that your website doesn't land on some index.
Search engines use web crawlers to index websites. This can cause unwanted traffic to your dashboard.
Homarr asks crawlers to not index your instance by default. Use these settings to change this request.
Homarr cannot control what the crawlers do. A crawler can ignore the request. Your website can still appear in an index.
### No index
This will ask crawlers to not index your Homarr instance on any indexes.
It is up to the crawler to properly respect this request.
By default, this setting is enabled. Disabling it will allow indexing.
This setting asks crawlers to not index your instance.
This setting is enabled by default. Disable this setting to allow indexing.
### No follow
If indexing is allowed, crawlers will also attempt to follow any links on your page to further "discover" new parts of the Internet and on your website.
By default, this setting is enabled and will ask crawlers to not follow any links.
Crawler of different companies may behave differently when indexing is prohibited and following is allowed.
Crawlers follow links to discover new pages.
This setting asks crawlers to not follow links. This setting is enabled by default.
Crawler behavior can differ between search engines.
### No translate
Google and Chrome on Android will prompt users to translate pages that are not in their device language.
This can lead to some shifting and can be undesired in some cases. By enabling this,
you ask crawlers to never translate and never prompt users for translation.
It should be noted that some browsers will ignore this and translate regardless.
Some browsers offer to translate pages.
This setting asks crawlers to not offer translation. Some browsers ignore this setting.
### No site links search box
This setting is exclusive to Google.
[Google will create a box below your domain](https://developers.google.com/search/docs/appearance/structured-data/sitelinks-searchbox) that lists the paths that were discovered by the "folowing".
The user can search them directly in Google.
You can ask the crawlers to not allow searches by enabling this setting.
This setting is disabled by default.
This setting applies to Google only.
Google can show a search box below your domain.
This setting asks Google to not show this box. This setting is disabled by default.
## Boards
### Global home board
You can set a global home board that will be used for all users that have not set a home board themselves.
It will also be used for anonymous users.
Note that the board must be public to be used as a global home board.
You can set a global home board.
This board is the fallback for users without their own home board. It is also the fallback for anonymous users.
The board must be public.
### Global mobile board
You can set a global mobile board. It will be shown instead of the global home board on mobile devices that can be detected by Homarr. (Using the User-Agent header).
It will similar to the global home board be as fallback for normal users and for any anonymous users.
It also has to be public.
You can set a global mobile board.
Homarr shows this board on mobile devices instead of the global home board.
Homarr detects mobile devices with the User-Agent header.
The board must be public.
### App status
#### Enable status by default
You can decide if the app status should be enabled by default when adding a new app to the board.
You can decide if app status is enabled when you add a new app.
#### Force disable status
You can decide if the app status should be disabled for all boards.
###
You can decide if app status is disabled on all boards.
## Appearance
### Default color scheme
You can set the default color scheme for all users that have not set a color scheme themselves.
You can set the default color scheme for users without their own color scheme.
## Culture
### Default language
You can set the default language for all users that have not set a language themselves.
You can set the default language for users without their own language.
+13 -15
View File
@@ -1,30 +1,27 @@
---
title: 'App'
description: 'Embeds an app into the board.'
title: "App"
description: "Embeds an app into the board."
hide_title: true
---
import { AddingWidget } from '@site/src/components/widgets/adding';
import { WidgetConfig } from '@site/src/components/widgets/configuration';
import { WidgetHeader } from '@site/src/components/widgets/header';
import { appWidget } from '.';
import { AddingWidget } from "@site/src/components/widgets/adding";
import { WidgetConfig } from "@site/src/components/widgets/configuration";
import { WidgetHeader } from "@site/src/components/widgets/header";
import { appWidget } from ".";
<WidgetHeader
widget={appWidget}
categories={['Links', 'Apps']}
/>
<WidgetHeader widget={appWidget} categories={["Links", "Apps"]} />
The app widget allows you to add a link to an application or a website that you want to access quickly from your Homarr board.
It also supports a status check to indicate whether Homarr can reach the application or website.
In view mode, right-clicking uses the browser's link menu. Homarr's widget menu remains available in edit mode.
### Screenshots
import githubApp from './img/github.png';
import jellyseerrApp from './img/jellyseerr-description-tooltip.png';
import piHoleApp from './img/pi-hole-ping-icon.png';
import githubApp from "./img/github.png";
import jellyseerrApp from "./img/jellyseerr-description-tooltip.png";
import piHoleApp from "./img/pi-hole-ping-icon.png";
<div className='flex gap-1'>
<div className="flex gap-1">
<img src={githubApp} alt="app github with-status-check" width={128 * 1.5} height={128 * 1.5} />
<img src={piHoleApp} alt="app pi-hole with-status-check status-check-icon" width={128 * 1.5} height={128 * 1.5} />
<img src={jellyseerrApp} alt="app jellyseerr with-description-tooltip" height={128 * 1.5} />
@@ -34,4 +31,5 @@ import piHoleApp from './img/pi-hole-ping-icon.png';
<AddingWidget />
### Configuration
<WidgetConfig configuration={appWidget.configuration} />
+24 -22
View File
@@ -1,43 +1,45 @@
---
title: 'Audio Stats'
description: 'Displays library statistics from Navidrome or Audiobookshelf, adapting its display based on the linked integration.'
title: "Audio Stats"
description: "Displays media and listening statistics from Navidrome or Audiobookshelf, adapting its display based on the linked integration."
hide_title: true
---
import { WidgetHeader } from '@site/src/components/widgets/header';
import { AddingWidget } from '@site/src/components/widgets/adding';
import { WidgetConfig } from '@site/src/components/widgets/configuration';
import { WidgetIntegrations } from '@site/src/components/widgets/integrations';
import { audioStatsWidget } from '.';
import { navidromeIntegration } from '@site/docs/integrations/navidrome';
import { audiobookshelfIntegration } from '@site/docs/integrations/audiobookshelf';
import { WidgetHeader } from "@site/src/components/widgets/header";
import { AddingWidget } from "@site/src/components/widgets/adding";
import { WidgetConfig } from "@site/src/components/widgets/configuration";
import { WidgetIntegrations } from "@site/src/components/widgets/integrations";
import { audioStatsWidget } from ".";
import { navidromeIntegration } from "@site/docs/integrations/navidrome";
import { audiobookshelfIntegration } from "@site/docs/integrations/audiobookshelf";
<WidgetHeader
widget={audioStatsWidget}
categories={['Media']}
/>
<WidgetHeader widget={audioStatsWidget} categories={["Media"]} />
This widget adapts its display based on the linked integration:
- **Navidrome**: Shows artist, album, and song counts, plus a now playing section with active streams
- **Navidrome**: Shows artist, album, and song counts
- **Audiobookshelf**: Shows library count, audiobook/podcast totals, listening time, and active sessions
Only options relevant to your linked integration are shown in the configuration panel.
### Supported Integrations
<WidgetIntegrations items={[{
integration: navidromeIntegration,
note: "Displays music library stats and now playing"
}, {
integration: audiobookshelfIntegration,
note: "Displays audiobook/podcast library stats and listening time"
}]} />
<WidgetIntegrations
items={[
{
integration: navidromeIntegration,
note: "Displays music library statistics",
},
{
integration: audiobookshelfIntegration,
note: "Displays audiobook/podcast library stats and listening time",
},
]}
/>
### Adding the widget
<AddingWidget />
### Configuration
<WidgetConfig configuration={audioStatsWidget.configuration} />
Loaded 100 of 921 files, more files were not shown because too many files have changed in this diff. Show more