Compare commits

..
185 Commits
Author SHA1 Message Date
Releases Homarr b6aa3afc6f chore(release): 1.54.0 [skip ci] 2026-02-27 19:33:48 +00:00
homarr-releases[bot] b959cac88f chore(release): automatic release v1.54.0 2026-02-27 19:32:47 +00:00
Meier Lukas 91fc5a5c74 Merge commit from fork
* fix(security): restrict access to integrations to authenticated users

* chore: github is broken
2026-02-27 19:24:24 +01:00
Meier Lukas fce970c706 Merge commit from fork
* fix(security): restrict rss-feed urls based on authentication

* fix: lint issues

* fix: incrase the limit to 100
2026-02-27 19:13:43 +01:00
homarr-update-contributors[bot] 9c6b2505a4 chore: update integrations list readme (#5134)
Co-authored-by: Homarr Update Contributors <210161987+homarr-update-contributors[bot]@users.noreply.github.com>
2026-02-27 16:09:00 +00:00
ManuelandMeier Lukas d999f37975 feat: add slskd integration (#5088)
Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
2026-02-27 17:04:27 +01:00
ManuelandMeier Lukas 91846bc000 feat: add glances integration (#5102)
Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
2026-02-27 16:57:29 +01:00
Meier Lukas c75c38e391 ci: on-release not triggered (#5058) 2026-02-27 16:43:39 +01:00
homarr-renovate[bot] cc63edf400 chore(deps): update dependency brace-expansion@&gt;&#x3d;2.0.0 &lt;&#x3d;2.0.1 to >=5.0.3 (#5133)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-27 13:09:40 +00:00
homarr-renovate[bot] 2ba6620343 chore(deps): update dependency rollup@&gt;&#x3d;4.0.0 &lt;4.22.4 to >=4.59.0 [security] (#5131)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-27 09:44:06 +00:00
homarr-crowdin[bot] 9c79a3bbcd 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-02-27 08:06:47 +00:00
homarr-renovate[bot] cfaf82cd04 fix(deps): update dependency isomorphic-dompurify to v3 (#5130)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-26 20:28:32 +01:00
homarr-crowdin[bot] 3f01d59180 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-02-26 19:17:51 +00:00
homarr-renovate[bot] 12ba14bb3f chore(deps): update dependency eslint to ^9.39.3 (#5127)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-25 14:58:57 +00:00
homarr-renovate[bot] f72ffb6558 chore(deps): update dependency rollup@&gt;&#x3d;4.0.0 &lt;4.22.4 to >=4.58.0 (#5126)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-25 13:14:01 +00:00
homarr-renovate[bot] 7ca38c3a78 fix(deps): update dependency mysql2 to v3.17.4 (#5123)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-25 11:00:55 +00:00
homarr-renovate[bot] 51585c6413 fix(deps): update dependency swagger-ui-react to ^5.31.2 (#5124)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-25 10:59:59 +00:00
homarr-renovate[bot] 6861839b65 fix(deps): update dependency fast-xml-parser to ^5.3.7 (#5122)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-25 06:08:40 +00:00
homarr-renovate[bot] 98488b55cd chore(deps): update pnpm to v10.30.1 (#5120)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-25 05:00:22 +00:00
homarr-renovate[bot] c3a4051007 fix(deps): update dependency @tabler/icons-react to ^3.37.1 (#5121)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-25 02:20:40 +00:00
homarr-renovate[bot] ba860193d7 fix(deps): update dependency @tabler/icons-react to ^3.37.0 (#5119)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-24 23:41:16 +00:00
homarr-renovate[bot] 908bced0df fix(deps): update dependency glob to ^13.0.6 (#5117)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-24 19:10:46 +00:00
homarr-renovate[bot] 42e53261ef fix(deps): update dependency mysql2 to v3.17.3 (#5116)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-24 16:07:35 +00:00
homarr-renovate[bot] 4aad0873ba fix(deps): update dependency jotai to ^2.18.0 (#5115)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-24 02:18:50 +00:00
homarr-crowdin[bot] fef3d8eac2 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-02-23 19:46:27 +00:00
homarr-renovate[bot] e3c8174bdc fix(deps): update testcontainers-node monorepo to ^11.12.0 (#5110)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-23 17:57:29 +00:00
homarr-renovate[bot] 3d2bc82a33 fix(deps): update tiptap monorepo to v3.20.0 (#5112)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-23 11:01:24 +00:00
homarr-renovate[bot] 61118d7a5e chore(deps): update pnpm to v10.30.0 (#5108)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-22 17:33:12 +00:00
homarr-renovate[bot] 02ec0898ef fix(deps): update dependency glob to ^13.0.5 (#5109)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-22 16:38:52 +00:00
homarr-renovate[bot] ea0a411c81 fix(deps): update dependency glob to ^13.0.4 (#5107)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-22 04:57:16 +00:00
homarr-renovate[bot] 210d46b43f fix(deps): update dependency swagger-ui-react to ^5.31.1 (#5101)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-22 04:57:00 +00:00
homarr-renovate[bot] 8bac6e1c5a fix(deps): update dependency typescript-eslint to ^8.56.0 (#5103)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-22 02:23:43 +00:00
homarr-renovate[bot] 15c7fc5ae8 fix(deps): update dependency mysql2 to v3.17.2 (#5104)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-22 02:21:23 +00:00
homarr-renovate[bot] ee6266707f fix(deps): update dependency @ctrl/qbittorrent to ^9.11.2 (#5106)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-22 02:20:02 +00:00
homarr-renovate[bot] dacbcce179 fix(deps): update dependency @ctrl/deluge to ^7.5.2 (#5105)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-21 23:31:41 +00:00
homarr-renovate[bot] d67c2db886 fix(deps): update dependency next-intl to v4.8.3 (#5100)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-21 09:39:00 +00:00
homarr-renovate[bot] 193d4d2e2a fix(deps): update dependency @ctrl/qbittorrent to ^9.11.1 (#5097)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-21 09:38:33 +00:00
homarr-renovate[bot] 53d46257ce fix(deps): update dependency @ctrl/deluge to ^7.5.1 (#5098)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-21 08:39:31 +00:00
homarr-renovate[bot] b8f9b4cf1d fix(deps): update mantine monorepo to ^8.3.15 (#5099)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-21 07:40:27 +00:00
Releases Homarr 37cfc75e51 chore(release): 1.53.2 [skip ci] 2026-02-20 19:36:56 +00:00
homarr-releases[bot] e714ebf87d chore(release): automatic release v1.53.2 2026-02-20 19:36:01 +00:00
Meier Lukas 8c4be2fbe8 fix(analytics): restrict publishing to every week (#5028) 2026-02-20 17:44:02 +01:00
homarr-renovate[bot] 24560cb93f fix(deps): update turbo monorepo to ^2.8.9 (#5092)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-20 13:08:07 +00:00
homarr-renovate[bot] 4183ea67c8 chore(deps): update dependency jsdom to ^28.1.0 (#5093)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-20 13:07:17 +00:00
homarr-update-contributors[bot] 98662a5daa chore: update contributors (#5051)
Co-authored-by: Homarr Update Contributors <210161987+homarr-update-contributors[bot]@users.noreply.github.com>
2026-02-20 12:49:42 +00:00
homarr-renovate[bot] 840d1107ec fix(deps): update dependency tsdav to ^2.1.8 (#5090)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-19 14:56:26 +00:00
homarr-renovate[bot] ac5bc70a5d fix(deps): update dependency fast-xml-parser to ^5.3.6 (#5089)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-19 11:46:36 +00:00
homarr-renovate[bot] 6be7cb6d1a chore(deps): update dependency brace-expansion@&gt;&#x3d;2.0.0 &lt;&#x3d;2.0.1 to v5 (#5075)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-19 12:05:48 +01:00
homarr-renovate[bot] b4186a3d0a chore(deps): update dependency vite-tsconfig-paths to ^6.1.1 (#5073)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-19 10:57:56 +00:00
homarr-renovate[bot] 8fcd73ff08 chore(deps): update dependency fast-xml-parser to v5.3.6 [security] (#5080)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-19 11:56:25 +01:00
homarr-renovate[bot] bb9da3007e fix(deps): update dependency react-error-boundary to ^6.1.1 (#5086)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-19 08:53:18 +00:00
homarr-renovate[bot] 475f14dc31 fix(deps): update dependency mysql2 to v3.17.1 (#5082)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-19 02:25:18 +00:00
homarr-renovate[bot] 46ba48fb20 fix(deps): update dependency dotenv to ^17.3.1 (#5081)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-19 02:23:28 +00:00
homarr-renovate[bot] bd6b0d7e5e chore(deps): update dependency @semantic-release/github to ^12.0.6 (#5077)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-18 23:38:34 +00:00
homarr-renovate[bot] dcae437fc5 fix(deps): update turbo monorepo to ^2.8.8 (#5084)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-18 22:42:44 +00:00
homarr-renovate[bot] 7e8f7447a5 chore(deps): update pnpm to v10.29.3 (#5070)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-17 21:45:31 +00:00
homarr-renovate[bot] 1e822fbe0c fix(deps): update dependency dotenv to ^17.3.0 (#5079)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-17 20:52:45 +00:00
homarr-renovate[bot] 4e1baa5703 fix(deps): update dependency ioredis to v5.9.3 (#5076)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-17 20:49:50 +00:00
homarr-renovate[bot] c6c48ea6e5 fix(deps): update turbo monorepo to ^2.8.7 (#5071)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-17 19:21:10 +00:00
homarr-renovate[bot] ba0ed77bb0 fix(deps): update dependency glob to ^13.0.3 (#5078)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-17 19:20:56 +00:00
homarr-renovate[bot] 1b8dde98d2 fix(deps): update dependency @tanstack/react-query to ^5.90.21 (#5067)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-17 18:06:26 +00:00
homarr-renovate[bot] 71fbb512f4 chore(deps): update node.js to v24.13.1 (#5055)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-17 17:04:32 +00:00
homarr-renovate[bot] 211a4dea05 chore(deps): update dependency @types/react to v19.2.14 (#5069)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-16 13:13:35 +00:00
homarr-renovate[bot] fcb020c191 fix(deps): update dependency mysql2 to v3.17.0 (#5066)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-16 11:51:45 +00:00
homarr-renovate[bot] 50601d5379 fix(deps): update dependency glob to ^13.0.2 (#5065)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-16 11:48:41 +00:00
homarr-renovate[bot] b04aa81490 chore(deps): update dependency @types/prismjs to ^1.26.6 (#5068)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-16 10:58:47 +00:00
homarr-renovate[bot] db14d98d19 fix(deps): update dependency drizzle-kit to ^0.31.9 (#5059)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-15 23:36:39 +00:00
homarr-renovate[bot] d4188120e1 chore(deps): update dependency @vitejs/plugin-react to ^5.1.4 (#5063)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-15 23:35:43 +00:00
homarr-renovate[bot] c36e947935 fix(deps): update turbo monorepo to ^2.8.5 (#5064)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-15 22:34:05 +00:00
homarr-renovate[bot] 56ecce2541 fix(deps): update dependency typescript-eslint to ^8.55.0 (#5061)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-15 02:33:11 +00:00
homarr-renovate[bot] 116eafa361 chore(deps): update pnpm to v10.29.2 (#5056)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-14 23:31:58 +00:00
homarr-renovate[bot] bc7ec63f85 fix(deps): update trpc monorepo to ^11.10.0 (#5062)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-14 22:32:34 +00:00
Releases Homarr 80fbbda111 chore(release): 1.53.1 [skip ci] 2026-02-13 19:42:07 +00:00
homarr-releases[bot] 72fcae1b85 chore(release): automatic release v1.53.1 2026-02-13 19:41:04 +00:00
Meier Lukas be1a26a98d fix(seerr): use reasonable limits for amount of returned entries (#5001) 2026-02-13 19:23:35 +01:00
homarr-renovate[bot] 30f561f85a fix(deps): update dependency fast-xml-parser to ^5.3.5 (#5050)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-13 15:49:24 +00:00
Meier Lukas 661d738302 ci: on-release pipeline no longer triggering and bug-report template not updated (#5048) 2026-02-13 15:43:48 +01:00
homarr-renovate[bot] 8002882979 chore(deps): update dependency hono@&lt;4.6.5 to >=4.11.9 (#5052)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-13 13:09:10 +00:00
homarr-renovate[bot] 5bd6cceaf1 chore(deps): update dependency @types/node to ^24.10.12 (#5045)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-13 07:18:22 +00:00
Meier Lukas 60fcb71bd2 fix(sections): dynamic sections vanish when adding category (#5046) 2026-02-13 08:05:15 +01:00
homarr-renovate[bot] 175d7d6324 chore(deps): update pnpm to v10.29.1 (#5043)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-12 19:58:05 +00:00
homarr-renovate[bot] 9e8701171b chore(deps): update dependency esbuild@&lt;&#x3d;0.24.2 to >=0.27.3 (#5031)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-12 19:46:18 +01:00
homarr-renovate[bot] 6568c22d86 chore(deps): update dependency esbuild to ^0.27.3 (#5030)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-12 19:46:02 +01:00
homarr-renovate[bot] e1a79afaaa chore(deps): update dependency vite-tsconfig-paths to ^6.1.0 (#5042)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-12 18:29:20 +00:00
homarr-renovate[bot] e561fc550f fix(deps): update dependency isomorphic-dompurify to ^2.36.0 (#5041)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-12 09:58:55 +00:00
homarr-renovate[bot] f2f16f0502 chore(deps): update dependency @semantic-release/github to ^12.0.5 (#5039)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-12 05:04:44 +00:00
homarr-renovate[bot] c92fd3a9ca chore(deps): update dependency @semantic-release/github to ^12.0.4 (#5037)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-11 22:38:11 +00:00
homarr-renovate[bot] 4dc04bb58b chore(deps): update dependency @semantic-release/npm to ^13.1.4 (#5035)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-11 20:47:43 +00:00
homarr-renovate[bot] d694b1a541 fix(deps): update dependency tsdav to ^2.1.7 (#5033)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-11 19:16:22 +00:00
homarr-renovate[bot] 0fff39ee1c chore(deps): update dependency hono@&lt;4.6.5 to >=4.11.8 (#5032)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-11 19:15:27 +00:00
homarr-renovate[bot] 6efabd4368 fix(deps): update dependency video.js to ^8.23.7 (#5034)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-11 18:03:26 +00:00
homarr-renovate[bot] 18e16d687f fix(deps): update dependency fastify to ^5.7.4 (#5027)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-10 21:54:36 +00:00
homarr-renovate[bot] e8c7f45476 fix(deps): update dependency dotenv to ^17.2.4 (#5029)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-10 21:04:17 +00:00
homarr-renovate[bot] 7bf5bbd035 chore(deps): update dependency jsdom to v28 (#5003)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-10 20:28:22 +01:00
homarr-renovate[bot]andMeier Lukas 29d9a9d288 chore(deps): update dependency fastify to v5.7.3 [security] (#4994)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
2026-02-10 20:05:12 +01:00
homarr-renovate[bot] 69d90c1ece chore(deps): update dependency @types/node to ^24.10.11 (#5025)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-10 15:07:49 +00:00
homarr-renovate[bot] 5946e6c719 fix(deps): update dependency @ianvs/prettier-plugin-sort-imports to ^4.7.1 (#5021)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-10 13:25:48 +00:00
homarr-renovate[bot] 74753c8918 chore(deps): update dependency @types/react to v19.2.13 (#5024)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-10 13:25:09 +00:00
homarr-renovate[bot] ef4ed16dc4 chore(deps): update dependency axios@&gt;&#x3d;1.0.0 &lt;1.8.2 to >=1.13.5 [security] (#5023)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-10 13:18:20 +00:00
homarr-renovate[bot] 49570417d4 chore(deps): update dependency @types/react to v19.2.12 (#5022)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-10 10:12:12 +00:00
homarr-renovate[bot] 98283ff526 chore(deps): update dependency @types/react to v19.2.11 (#5020)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-09 11:52:32 +00:00
homarr-renovate[bot] da965668d0 fix(deps): update dependency jotai to ^2.17.1 (#5019)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-09 05:08:24 +00:00
homarr-renovate[bot] c92d487cea fix(deps): update dependency ldapts to v8.1.6 (#5018)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-09 02:31:43 +00:00
homarr-crowdin[bot] 81cecbfb57 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-02-09 01:11:26 +00:00
homarr-renovate[bot] f1d2f07f38 fix(deps): update turbo monorepo to ^2.8.3 (#5016)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-08 23:40:57 +00:00
homarr-renovate[bot] 04b35980f5 fix(deps): update dependency mysql2 to v3.16.3 (#5014)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-08 18:47:39 +00:00
homarr-renovate[bot] 3b21c3ef76 fix(deps): update dependency glob to ^13.0.1 (#5013)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-08 18:45:16 +00:00
homarr-renovate[bot] ad41a918ef fix(deps): update tiptap monorepo to v3.19.0 (#5012)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-08 17:35:55 +00:00
homarr-crowdin[bot] 0b654aeafa chore(lang): update translations from crowdin (#5002)
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-02-08 14:03:04 +01:00
homarr-renovate[bot] 9e9b904f69 chore(deps): update dependency @types/node to ^24.10.10 (#5011)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-08 09:39:25 +00:00
homarr-renovate[bot] b479fea6eb fix(deps): update turbo monorepo to ^2.8.2 (#5010)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-08 06:59:58 +00:00
homarr-renovate[bot] 4a86361134 fix(deps): update dependency @octokit/auth-app to ^8.2.0 (#5009)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-08 02:45:18 +00:00
homarr-renovate[bot] b67fecd396 fix(deps): update dependency next-intl to v4.8.2 (#5005)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-07 11:30:58 +00:00
homarr-renovate[bot] 075ddb7a83 chore(deps): update dependency @vitejs/plugin-react to ^5.1.3 (#5006)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-07 10:38:18 +00:00
homarr-renovate[bot] c3932b18f0 fix(deps): update dependency ldapts to v8.1.5 (#5004)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-07 09:41:54 +00:00
Releases Homarr 6dd13f6dea chore(release): 1.53.0 [skip ci] 2026-02-06 19:37:59 +00:00
homarr-releases[bot] 129d96f607 chore(release): automatic release v1.53.0 2026-02-06 19:37:00 +00:00
homarr-renovate[bot] 0fafa505ac fix(deps): update mantine monorepo to ^8.3.14 (#4998)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-06 13:10:10 +00:00
homarr-crowdin[bot] 5e085b0da0 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-02-06 01:04:58 +00:00
homarr-renovate[bot] c2d9f18e4e fix(deps): update dependency ldapts to v8.1.4 (#4993)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-05 14:50:32 +00:00
homarr-renovate[bot] 4209f7c70e fix(deps): update dependency video.js to ^8.23.6 (#4992)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-05 11:43:25 +00:00
ajnart 10848db595 feat(analytics): consolidate server analytics into single comprehensive Umami event (#4938)
* feat(analytics): consolidate server analytics into single Umami event

- Replace multiple separate events with single 'server-analytics' event
- Add comprehensive metrics: Homarr version, database type, Docker/K8s status
- Add auth providers status (credentials, OIDC, LDAP)
- Add counts for users, boards, groups, apps, widgets, sections, integrations
- Add counts for search engines, icon repos, icons, API keys, invites, media
- Add counts for layouts, item layouts, section layouts, cron job configs
- Include per-integration-kind breakdown (integration_sonarr, etc.)
- Add required dependencies: @homarr/auth, @homarr/common, @homarr/docker

* refactor(ui): simplify analytics settings to single toggle

- Remove individual toggles for widget/integration/user data
- Keep only the main 'Enable analytics' toggle
- All data is now collected when analytics are enabled
- Update both init settings and manage settings pages

* docs(i18n): update analytics description with collected data details

- Explain all data points collected when analytics are enabled
- List: version, DB type, Docker/K8s, auth methods, counts
- Clarify that no personal info, URLs, or names are collected

* chore(deps): update pnpm-lock.yaml for analytics package dependencies
2026-02-05 09:54:41 +01:00
homarr-renovate[bot] 43b6246876 fix(deps): update turbo monorepo to ^2.8.1 (#4991)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-04 22:37:10 +00:00
homarr-renovate[bot] bd07570c8d chore(deps): update semantic-release monorepo (#4990)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-04 21:41:31 +00:00
homarr-renovate[bot] 62b6939b92 fix(deps): update dependency next-intl to v4.8.1 (#4986)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-04 19:46:39 +00:00
homarr-renovate[bot] c3071a3c95 fix(deps): update dependency pg to ^8.18.0 (#4989)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-04 19:00:45 +00:00
homarr-renovate[bot] 1115ad1364 fix(deps): update dependency @tanstack/react-query-devtools to ^5.91.3 (#4985)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-04 09:51:43 +00:00
homarr-renovate[bot] 4cfd2aca94 chore(deps): update dependency rollup@&gt;&#x3d;4.0.0 &lt;4.22.4 to >=4.57.1 (#4984)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-04 08:49:28 +00:00
homarr-renovate[bot] 460d53cafa fix(deps): update dependency fast-xml-parser to ^5.3.4 (#4982)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-04 04:47:35 +00:00
homarr-crowdin[bot] 0b88d5703e chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-02-03 01:09:22 +00:00
homarr-renovate[bot] 054ca57188 fix(deps): update turbo monorepo to ^2.8.0 (#4978)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-02 18:54:38 +00:00
homarr-renovate[bot] c3a7ab52ee fix(deps): update dependency next-intl to v4.8.0 (#4977)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-02 17:46:05 +00:00
homarr-crowdin[bot] 8ee1e32e83 chore(lang): update translations from crowdin (#4954)
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-02-02 17:24:22 +01:00
homarr-renovate[bot] 24e24dc634 fix(deps): update tiptap monorepo to v3.18.0 (#4975)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-02 13:09:45 +00:00
homarr-renovate[bot] 6303aec209 chore(deps): update dependency fast-xml-parser to v5.3.4 [security] (#4974)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-02 07:53:26 +00:00
homarr-renovate[bot] 7c3fe3d6d4 fix(deps): update nextjs monorepo to v16.1.6 (#4969)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-02 05:05:02 +00:00
homarr-renovate[bot] e67483fea5 fix(deps): update dependency jotai to ^2.17.0 (#4972)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-02 02:29:58 +00:00
homarr-renovate[bot] d1f7e04a2a chore(deps): update dependency proxmox-api&gt;undici to v7.19.2 (#4967)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-02 02:28:37 +00:00
homarr-renovate[bot] 0a2f71bd31 chore(deps): update dependency rollup@&gt;&#x3d;4.0.0 &lt;4.22.4 to >=4.57.0 (#4963)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-01 23:34:08 +00:00
homarr-renovate[bot] aeb6e0f406 fix(deps): update trpc monorepo to ^11.9.0 (#4970)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-01 22:34:19 +00:00
homarr-renovate[bot] df264f58d0 chore(deps): update dependency @types/react to v19.2.10 (#4964)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-01 19:31:41 +00:00
homarr-renovate[bot] 71aa5b660b chore(deps): update dependency axios@&gt;&#x3d;1.0.0 &lt;1.8.2 to >=1.13.4 (#4966)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-02-01 18:42:55 +00:00
homarr-renovate[bot] 5c6eafb272 fix(deps): update dependency mysql2 to v3.16.2 (#4961)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-31 21:30:15 +00:00
homarr-renovate[bot] e88d126355 fix(deps): update dependency typescript-eslint to ^8.54.0 (#4958)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-31 19:28:39 +00:00
homarr-renovate[bot] d3e0b47875 fix(deps): update react monorepo to v19.2.4 (#4960)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-31 18:42:46 +00:00
homarr-renovate[bot] ec40309cde fix(deps): update dependency @next/eslint-plugin-next to v16.1.5 (#4959)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-31 18:42:21 +00:00
homarr-renovate[bot] a3ba70177b chore(deps): update pnpm to v10.28.2 (#4956)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-31 15:32:24 +00:00
homarr-renovate[bot] 0eab26cdac fix(deps): update dependency fastify to ^5.7.2 (#4955)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-31 11:27:34 +00:00
homarr-renovate[bot] a9db68bd3e fix(deps): update dependency @paralleldrive/cuid2 to ^3.3.0 (#4952)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-30 21:36:03 +00:00
Releases Homarr d2c075517f chore(release): 1.52.0 [skip ci] 2026-01-30 19:32:17 +00:00
homarr-releases[bot] fab80d5ab2 chore(release): automatic release v1.52.0 2026-01-30 19:31:27 +00:00
Meier Lukasandajnart 8811af5e6e Merge commit from fork
* fix(security): resolve ssrf issue with simple ping

* refactor: improve testability of app-access-control and fix tests

* fix: unnecessary space

Co-authored-by: ajnart <thomas@ajnart.fr>

---------

Co-authored-by: ajnart <thomas@ajnart.fr>
2026-01-30 18:31:13 +01:00
Meier Lukas 9ba82133da feat(installations): support docker secrets file for encryption key (#4946) 2026-01-30 17:28:08 +01:00
homarr-renovate[bot] 67e1b9bdc3 chore(deps): update dependency axios@&gt;&#x3d;1.0.0 &lt;1.8.2 to >=1.13.3 (#4950)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-30 14:52:11 +00:00
homarr-renovate[bot] 08711a551f chore(deps): update dependency hono@&lt;4.6.5 to >=4.11.7 [security] (#4930)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-30 14:01:18 +00:00
homarr-update-contributors[bot] ef1197b382 chore: update contributors (#4949)
Co-authored-by: Homarr Update Contributors <210161987+homarr-update-contributors[bot]@users.noreply.github.com>
2026-01-30 12:45:40 +00:00
homarr-crowdin[bot] 26144e22f4 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-01-30 01:05:18 +00:00
homarr-renovate[bot] e078237e31 fix(deps): update turbo monorepo to ^2.7.6 (#4947)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-29 22:36:34 +00:00
Meier Lukas 1a33d8ccee chore: ignore .turbo directory for docker build 2026-01-29 20:37:01 +01:00
homarr-renovate[bot] b354085c7a fix(deps): update tiptap monorepo to v3.17.1 (#4945)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-29 18:56:43 +00:00
homarr-crowdin[bot] a43429b351 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-01-29 18:49:45 +00:00
homarr-renovate[bot] 203ebbbd4e chore(deps): update dependency proxmox-api&gt;undici to v7.19.1 (#4944)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-29 15:44:22 +00:00
homarr-renovate[bot] 0bdc76cc23 chore(deps): update dependency vite-tsconfig-paths to ^6.0.5 (#4941)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-28 22:35:54 +00:00
homarr-renovate[bot] 840940bab6 fix(deps): update dependency @tanstack/react-query to ^5.90.20 (#4939)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-28 14:38:30 +00:00
homarr-renovate[bot] d03026187c fix(deps): update tiptap monorepo to v3.17.0 (#4940)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-28 13:58:20 +00:00
homarr-renovate[bot] aeb1df1229 fix(deps): update dependency next to v16.1.5 [security] (#4937)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-27 21:21:21 +00:00
homarr-renovate[bot] dea3f02e6f chore(deps): update vitest monorepo to ^4.0.18 (#4929)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-27 20:40:04 +01:00
homarr-renovate[bot] 6fd0fb5508 chore(deps): update dependency prettier-plugin-packagejson to v3 (#4910)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-27 17:16:26 +01:00
homarr-renovate[bot] ce72b21a04 chore(deps): update dependency rollup@&gt;&#x3d;4.0.0 &lt;4.22.4 to >=4.56.0 (#4928)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-27 06:43:47 +00:00
homarr-renovate[bot] b1658a5d01 fix(deps): update dependency sass to ^1.97.3 (#4927)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-27 03:55:45 +00:00
homarr-renovate[bot] 4df63eacc5 chore(deps): update dependency hono@&lt;4.6.5 to >=4.11.5 (#4926)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-27 02:02:21 +00:00
homarr-renovate[bot] 3cca339881 chore(deps): update dependency rollup@&gt;&#x3d;4.0.0 &lt;4.22.4 to >=4.55.3 (#4919)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-26 20:35:32 +00:00
homarr-renovate[bot] fd18cf79cc chore(deps): update dependency proxmox-api&gt;undici to v7.19.0 (#4922)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-26 19:31:50 +00:00
homarr-renovate[bot] a727b8e323 fix(deps): update dependency prettier to ^3.8.1 (#4925)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-26 18:45:54 +00:00
homarr-renovate[bot] 21c3882189 chore(deps): update dependency @types/dockerode to ^4.0.1 (#4918)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-26 04:08:39 +00:00
homarr-renovate[bot] d0c27b22ef chore(deps): update dependency @types/react to v19.2.9 (#4914)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-25 19:25:21 +00:00
homarr-renovate[bot] a50a29a778 fix(deps): update dependency pg to ^8.17.2 (#4916)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-25 18:39:14 +00:00
homarr-renovate[bot] 23545101b6 fix(deps): update tiptap monorepo to v3.16.0 (#4912)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-25 12:52:13 +00:00
homarr-renovate[bot] f2eec74849 fix(deps): update mantine monorepo to ^8.3.13 (#4911)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-25 07:29:50 +00:00
homarr-renovate[bot] 99a2574d80 fix(deps): update nextjs monorepo to v16.1.4 (#4909)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-25 02:08:32 +00:00
homarr-crowdin[bot] 66bde23667 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-01-25 01:02:57 +00:00
homarr-renovate[bot] c58da00957 fix(deps): update dependency typescript-eslint to ^8.53.1 (#4904)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-24 17:26:34 +00:00
homarr-renovate[bot] 6700124ccd chore(deps): update dependency rollup@&gt;&#x3d;4.0.0 &lt;4.22.4 to >=4.55.2 (#4902)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-24 13:37:13 +00:00
homarr-renovate[bot] f428abc0ce chore(deps): update pnpm to v10.28.1 (#4903)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-01-24 12:50:35 +00:00
homarr-crowdin[bot] 16e3e5b90b chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2026-01-24 00:55:54 +00:00
120 changed files with 8549 additions and 6111 deletions

No files matched your search

+1
View File
@@ -5,6 +5,7 @@ node_modules
npm-debug.log
README.md
.next
.turbo
.git
dev
.build
+6
View File
@@ -33,6 +33,12 @@ body:
options:
# The below comment is used to insert a new version with on-release.yml
#NEXT_VERSION#
- 1.53.0
- 1.52.0
- 1.51.0
- 1.50.1
- 1.50.0
- 1.49.1
- 1.49.0
- 1.48.0
- 1.47.0
+11 -2
View File
@@ -65,7 +65,7 @@ jobs:
- uses: actions/setup-node@v6
if: env.SKIP_RELEASE == 'false'
with:
node-version: 24.13.0
node-version: 24.13.1
cache: "pnpm"
- run: npm i -g pnpm
if: env.SKIP_RELEASE == 'false'
@@ -228,6 +228,15 @@ jobs:
DEPLOY_LATEST: ${{ github.ref_name == 'main' }}
DEPLOY_BETA: ${{ github.ref_name == 'beta' }}
steps:
- name: Obtain token
if: needs.release.outputs.skipped == 'false'
id: obtainToken
uses: actions/create-github-app-token@v2
with:
private-key: ${{ secrets.RENOVATE_MERGE_PRIVATE_KEY }}
app-id: ${{ secrets.RENOVATE_MERGE_APP_ID }}
permission-contents: write # required to publish the release
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
@@ -258,7 +267,7 @@ jobs:
- name: Publish release
if: needs.release.outputs.skipped == 'false'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
run: |
gh release edit --repo ${{ github.repository }} ${{ needs.release.outputs.version }} --draft=false
+7 -9
View File
@@ -2,7 +2,7 @@ permissions: {}
on:
release:
types: [published]
types: [released]
jobs:
trigger-docs-release:
@@ -37,6 +37,7 @@ jobs:
}
}
EOF
update-bug-report-template:
name: Update Bug Report Template
runs-on: ubuntu-latest
@@ -54,23 +55,20 @@ jobs:
uses: actions/checkout@v6
with:
token: ${{ steps.obtainToken.outputs.token }}
ref: dev
- name: Setup
uses: ./tooling/github/setup
- run: pnpm run scripts:update-bug-report-template
env:
NEXT_VERSION: ${{ github.event.release.tag_name }}
- name: Commit changes
run: |
git config --global user.email "175486441+homarr-releases[bot]@users.noreply.github.com"
git config --global user.name "Releases Homarr"
git checkout -b update-bug-report-template
git add .
git commit -m "chore: update bug report template"
- name: Create Pull Request
id: create-pull-request
uses: peter-evans/create-pull-request@v8
uses: peter-evans/create-pull-request@v7
with:
add-paths: .github/ISSUE_TEMPLATE/bug_report.yml
commit-message: "chore: update bug report template"
author: Releases Homarr <175486441+homarr-releases[bot]@users.noreply.github.com>
token: ${{ steps.obtainToken.outputs.token }}
branch: update-bug-report-template
base: dev
+1 -1
View File
@@ -1 +1 @@
24.13.0
24.13.1
+130
View File
@@ -1,3 +1,133 @@
## [1.54.0](https://github.com/homarr-labs/homarr/compare/v1.53.2...v1.54.0) (2026-02-27)
### Features
* add glances integration ([#5102](https://github.com/homarr-labs/homarr/issues/5102)) ([91846bc](https://github.com/homarr-labs/homarr/commit/91846bc000b419b03925acc4b447efcc696ff009))
* add slskd integration ([#5088](https://github.com/homarr-labs/homarr/issues/5088)) ([d999f37](https://github.com/homarr-labs/homarr/commit/d999f3797562a4c1d07a08b10ef4821c12390d2f))
### Bug Fixes
* **deps:** update dependency @ctrl/deluge to ^7.5.1 ([#5098](https://github.com/homarr-labs/homarr/issues/5098)) ([53d4625](https://github.com/homarr-labs/homarr/commit/53d46257ce2c257f2e083d0645178823afd45227))
* **deps:** update dependency @ctrl/deluge to ^7.5.2 ([#5105](https://github.com/homarr-labs/homarr/issues/5105)) ([dacbcce](https://github.com/homarr-labs/homarr/commit/dacbcce179c21f8858f61633c4a72b248ec437b7))
* **deps:** update dependency @ctrl/qbittorrent to ^9.11.1 ([#5097](https://github.com/homarr-labs/homarr/issues/5097)) ([193d4d2](https://github.com/homarr-labs/homarr/commit/193d4d2e2aabaffb019108c3150de3f92d84efe8))
* **deps:** update dependency @ctrl/qbittorrent to ^9.11.2 ([#5106](https://github.com/homarr-labs/homarr/issues/5106)) ([ee62667](https://github.com/homarr-labs/homarr/commit/ee6266707f779e7a080b40b4ed3e0a8679bb2910))
* **deps:** update dependency @tabler/icons-react to ^3.37.0 ([#5119](https://github.com/homarr-labs/homarr/issues/5119)) ([ba86019](https://github.com/homarr-labs/homarr/commit/ba860193d78f84fa9326a006caba4b3cc7c195c2))
* **deps:** update dependency @tabler/icons-react to ^3.37.1 ([#5121](https://github.com/homarr-labs/homarr/issues/5121)) ([c3a4051](https://github.com/homarr-labs/homarr/commit/c3a40510075f56d7f156c877e1041b7bf36677b5))
* **deps:** update dependency fast-xml-parser to ^5.3.7 ([#5122](https://github.com/homarr-labs/homarr/issues/5122)) ([6861839](https://github.com/homarr-labs/homarr/commit/6861839b65fffb0c8030ae7a6fd24105fdad6b95))
* **deps:** update dependency glob to ^13.0.4 ([#5107](https://github.com/homarr-labs/homarr/issues/5107)) ([ea0a411](https://github.com/homarr-labs/homarr/commit/ea0a411c813c8dfcb17493e6a41d2ab96077adb6))
* **deps:** update dependency glob to ^13.0.5 ([#5109](https://github.com/homarr-labs/homarr/issues/5109)) ([02ec089](https://github.com/homarr-labs/homarr/commit/02ec0898ef32f8b6ac540a9c005130f3e7312e65))
* **deps:** update dependency glob to ^13.0.6 ([#5117](https://github.com/homarr-labs/homarr/issues/5117)) ([908bced](https://github.com/homarr-labs/homarr/commit/908bced0dfb158a9da155c97dbf982c2d544fc20))
* **deps:** update dependency isomorphic-dompurify to v3 ([#5130](https://github.com/homarr-labs/homarr/issues/5130)) ([cfaf82c](https://github.com/homarr-labs/homarr/commit/cfaf82cd04e4659db50e6074fce4cc739ee2aaf8))
* **deps:** update dependency jotai to ^2.18.0 ([#5115](https://github.com/homarr-labs/homarr/issues/5115)) ([4aad087](https://github.com/homarr-labs/homarr/commit/4aad0873baec97167460bad1c69c770aecb38bd0))
* **deps:** update dependency mysql2 to v3.17.2 ([#5104](https://github.com/homarr-labs/homarr/issues/5104)) ([15c7fc5](https://github.com/homarr-labs/homarr/commit/15c7fc5ae809b671c8d774d39b7a7fdf893db611))
* **deps:** update dependency mysql2 to v3.17.3 ([#5116](https://github.com/homarr-labs/homarr/issues/5116)) ([42e5326](https://github.com/homarr-labs/homarr/commit/42e53261ef956a0f5ad60ac45c623d3acd3d9530))
* **deps:** update dependency mysql2 to v3.17.4 ([#5123](https://github.com/homarr-labs/homarr/issues/5123)) ([7ca38c3](https://github.com/homarr-labs/homarr/commit/7ca38c3a781d54f91d01844e077528345a9b190b))
* **deps:** update dependency next-intl to v4.8.3 ([#5100](https://github.com/homarr-labs/homarr/issues/5100)) ([d67c2db](https://github.com/homarr-labs/homarr/commit/d67c2db886b92e7d0973bf17ff5059b8328acdf6))
* **deps:** update dependency swagger-ui-react to ^5.31.1 ([#5101](https://github.com/homarr-labs/homarr/issues/5101)) ([210d46b](https://github.com/homarr-labs/homarr/commit/210d46b43ffeb956af3f983a82772609e42f08df))
* **deps:** update dependency swagger-ui-react to ^5.31.2 ([#5124](https://github.com/homarr-labs/homarr/issues/5124)) ([51585c6](https://github.com/homarr-labs/homarr/commit/51585c6413ab3841f0bee1e736d726081912ab08))
* **deps:** update dependency typescript-eslint to ^8.56.0 ([#5103](https://github.com/homarr-labs/homarr/issues/5103)) ([8bac6e1](https://github.com/homarr-labs/homarr/commit/8bac6e1c5a239108bc48fd877b3fc1ec8b445109))
* **deps:** update mantine monorepo to ^8.3.15 ([#5099](https://github.com/homarr-labs/homarr/issues/5099)) ([b8f9b4c](https://github.com/homarr-labs/homarr/commit/b8f9b4cf1d870956806a68ad78a95af60c99975f))
* **deps:** update testcontainers-node monorepo to ^11.12.0 ([#5110](https://github.com/homarr-labs/homarr/issues/5110)) ([e3c8174](https://github.com/homarr-labs/homarr/commit/e3c8174bdcb95de8e731c79c2b4bebce98d6dbce))
* **deps:** update tiptap monorepo to v3.20.0 ([#5112](https://github.com/homarr-labs/homarr/issues/5112)) ([3d2bc82](https://github.com/homarr-labs/homarr/commit/3d2bc82a33a88a8f2d60fd61112f1f712e956670))
## [1.53.2](https://github.com/homarr-labs/homarr/compare/v1.53.1...v1.53.2) (2026-02-20)
### Bug Fixes
* **analytics:** restrict publishing to every week ([#5028](https://github.com/homarr-labs/homarr/issues/5028)) ([8c4be2f](https://github.com/homarr-labs/homarr/commit/8c4be2fbe80e42472b8b17542a4282ec26d1fefe))
* **deps:** update dependency @tanstack/react-query to ^5.90.21 ([#5067](https://github.com/homarr-labs/homarr/issues/5067)) ([1b8dde9](https://github.com/homarr-labs/homarr/commit/1b8dde98d2518d3d82895a26a58db7f42abf2a6e))
* **deps:** update dependency dotenv to ^17.3.0 ([#5079](https://github.com/homarr-labs/homarr/issues/5079)) ([1e822fb](https://github.com/homarr-labs/homarr/commit/1e822fbe0c8224e6ba5b99e6516ea4437c9f36bb))
* **deps:** update dependency dotenv to ^17.3.1 ([#5081](https://github.com/homarr-labs/homarr/issues/5081)) ([46ba48f](https://github.com/homarr-labs/homarr/commit/46ba48fb20b69b2876fc42ee862a64717e6428f7))
* **deps:** update dependency drizzle-kit to ^0.31.9 ([#5059](https://github.com/homarr-labs/homarr/issues/5059)) ([db14d98](https://github.com/homarr-labs/homarr/commit/db14d98d1966dada5d74507e64e90f34fb4eee60))
* **deps:** update dependency fast-xml-parser to ^5.3.6 ([#5089](https://github.com/homarr-labs/homarr/issues/5089)) ([ac5bc70](https://github.com/homarr-labs/homarr/commit/ac5bc70a5de9a4307c4165203ff26ee1a112ca81))
* **deps:** update dependency glob to ^13.0.2 ([#5065](https://github.com/homarr-labs/homarr/issues/5065)) ([50601d5](https://github.com/homarr-labs/homarr/commit/50601d53792baae5a259adb4e4d3fefcc35d25df))
* **deps:** update dependency glob to ^13.0.3 ([#5078](https://github.com/homarr-labs/homarr/issues/5078)) ([ba0ed77](https://github.com/homarr-labs/homarr/commit/ba0ed77bb036dd0e35db08ce9df98f133f835d53))
* **deps:** update dependency ioredis to v5.9.3 ([#5076](https://github.com/homarr-labs/homarr/issues/5076)) ([4e1baa5](https://github.com/homarr-labs/homarr/commit/4e1baa570324be06eb442f2db08a8b152d9b416b))
* **deps:** update dependency mysql2 to v3.17.0 ([#5066](https://github.com/homarr-labs/homarr/issues/5066)) ([fcb020c](https://github.com/homarr-labs/homarr/commit/fcb020c191b98a729508b7660fb484f29208c51c))
* **deps:** update dependency mysql2 to v3.17.1 ([#5082](https://github.com/homarr-labs/homarr/issues/5082)) ([475f14d](https://github.com/homarr-labs/homarr/commit/475f14dc312c1b8cffbabe607c17be8b2d1d294c))
* **deps:** update dependency react-error-boundary to ^6.1.1 ([#5086](https://github.com/homarr-labs/homarr/issues/5086)) ([bb9da30](https://github.com/homarr-labs/homarr/commit/bb9da3007e4f29fd7993bd9960e80e316a17bbf0))
* **deps:** update dependency tsdav to ^2.1.8 ([#5090](https://github.com/homarr-labs/homarr/issues/5090)) ([840d110](https://github.com/homarr-labs/homarr/commit/840d1107ec3392b4581c931ef1efe2d9816ededd))
* **deps:** update dependency typescript-eslint to ^8.55.0 ([#5061](https://github.com/homarr-labs/homarr/issues/5061)) ([56ecce2](https://github.com/homarr-labs/homarr/commit/56ecce254195c480eef9cefefd7bad98c49b9175))
* **deps:** update trpc monorepo to ^11.10.0 ([#5062](https://github.com/homarr-labs/homarr/issues/5062)) ([bc7ec63](https://github.com/homarr-labs/homarr/commit/bc7ec63f8547e8f868ef5d56a1a8c5c893fda1e3))
* **deps:** update turbo monorepo to ^2.8.5 ([#5064](https://github.com/homarr-labs/homarr/issues/5064)) ([c36e947](https://github.com/homarr-labs/homarr/commit/c36e947935246761cac26049ac24c56c8cc0990a))
* **deps:** update turbo monorepo to ^2.8.7 ([#5071](https://github.com/homarr-labs/homarr/issues/5071)) ([c6c48ea](https://github.com/homarr-labs/homarr/commit/c6c48ea6e5f76303fd93022fd566a99af1ad829f))
* **deps:** update turbo monorepo to ^2.8.8 ([#5084](https://github.com/homarr-labs/homarr/issues/5084)) ([dcae437](https://github.com/homarr-labs/homarr/commit/dcae437fc5cadc2e112037fa26f8351111c69869))
* **deps:** update turbo monorepo to ^2.8.9 ([#5092](https://github.com/homarr-labs/homarr/issues/5092)) ([24560cb](https://github.com/homarr-labs/homarr/commit/24560cb93f17767b5ab8047c07f81a165e0fb769))
## [1.53.1](https://github.com/homarr-labs/homarr/compare/v1.53.0...v1.53.1) (2026-02-13)
### Bug Fixes
* **deps:** update dependency @ianvs/prettier-plugin-sort-imports to ^4.7.1 ([#5021](https://github.com/homarr-labs/homarr/issues/5021)) ([5946e6c](https://github.com/homarr-labs/homarr/commit/5946e6c7193eded77b98c76aedff71a7bb912574))
* **deps:** update dependency @octokit/auth-app to ^8.2.0 ([#5009](https://github.com/homarr-labs/homarr/issues/5009)) ([4a86361](https://github.com/homarr-labs/homarr/commit/4a86361134da404462b1a9f8ff98fe3504fade0d))
* **deps:** update dependency dotenv to ^17.2.4 ([#5029](https://github.com/homarr-labs/homarr/issues/5029)) ([e8c7f45](https://github.com/homarr-labs/homarr/commit/e8c7f454768044540ee37d75fc73654b74315390))
* **deps:** update dependency fast-xml-parser to ^5.3.5 ([#5050](https://github.com/homarr-labs/homarr/issues/5050)) ([30f561f](https://github.com/homarr-labs/homarr/commit/30f561f85ad2abb90ccb9fa3292155d51f1f379b))
* **deps:** update dependency fastify to ^5.7.4 ([#5027](https://github.com/homarr-labs/homarr/issues/5027)) ([18e16d6](https://github.com/homarr-labs/homarr/commit/18e16d687f8137e5b5c55cf2385436b714a2d27b))
* **deps:** update dependency glob to ^13.0.1 ([#5013](https://github.com/homarr-labs/homarr/issues/5013)) ([3b21c3e](https://github.com/homarr-labs/homarr/commit/3b21c3ef765add0f7cdc8f66ae8f1b7aac3cf51e))
* **deps:** update dependency isomorphic-dompurify to ^2.36.0 ([#5041](https://github.com/homarr-labs/homarr/issues/5041)) ([e561fc5](https://github.com/homarr-labs/homarr/commit/e561fc550fab2207212ae108a5177a248795cf66))
* **deps:** update dependency jotai to ^2.17.1 ([#5019](https://github.com/homarr-labs/homarr/issues/5019)) ([da96566](https://github.com/homarr-labs/homarr/commit/da965668d021ebebd8c8a7e2a4560577a6b0828b))
* **deps:** update dependency ldapts to v8.1.5 ([#5004](https://github.com/homarr-labs/homarr/issues/5004)) ([c3932b1](https://github.com/homarr-labs/homarr/commit/c3932b18f03b86e8ee049c14ace63119fd2ab0d6))
* **deps:** update dependency ldapts to v8.1.6 ([#5018](https://github.com/homarr-labs/homarr/issues/5018)) ([c92d487](https://github.com/homarr-labs/homarr/commit/c92d487ceaa9159579ef4352d763429887953bb5))
* **deps:** update dependency mysql2 to v3.16.3 ([#5014](https://github.com/homarr-labs/homarr/issues/5014)) ([04b3598](https://github.com/homarr-labs/homarr/commit/04b35980f5997e744a455a847f28b1a676f9861e))
* **deps:** update dependency next-intl to v4.8.2 ([#5005](https://github.com/homarr-labs/homarr/issues/5005)) ([b67fecd](https://github.com/homarr-labs/homarr/commit/b67fecd3963bc3112ab8ecd91385bbe13c982290))
* **deps:** update dependency tsdav to ^2.1.7 ([#5033](https://github.com/homarr-labs/homarr/issues/5033)) ([d694b1a](https://github.com/homarr-labs/homarr/commit/d694b1a5410833a791d57fb3dd4650003510140e))
* **deps:** update dependency video.js to ^8.23.7 ([#5034](https://github.com/homarr-labs/homarr/issues/5034)) ([6efabd4](https://github.com/homarr-labs/homarr/commit/6efabd436849b9fdea0d060fe7beaa9c67424c29))
* **deps:** update tiptap monorepo to v3.19.0 ([#5012](https://github.com/homarr-labs/homarr/issues/5012)) ([ad41a91](https://github.com/homarr-labs/homarr/commit/ad41a918ef72f322015a02e9601c43728e680b34))
* **deps:** update turbo monorepo to ^2.8.2 ([#5010](https://github.com/homarr-labs/homarr/issues/5010)) ([b479fea](https://github.com/homarr-labs/homarr/commit/b479fea6eb0b025b55668201160a5e57267de2e7))
* **deps:** update turbo monorepo to ^2.8.3 ([#5016](https://github.com/homarr-labs/homarr/issues/5016)) ([f1d2f07](https://github.com/homarr-labs/homarr/commit/f1d2f07f3888e7567b56ae61a9d137255a2b8529))
* **sections:** dynamic sections vanish when adding category ([#5046](https://github.com/homarr-labs/homarr/issues/5046)) ([60fcb71](https://github.com/homarr-labs/homarr/commit/60fcb71bd2616af3e99b20cbbcd1b0417a0fff76))
* **seerr:** use reasonable limits for amount of returned entries ([#5001](https://github.com/homarr-labs/homarr/issues/5001)) ([be1a26a](https://github.com/homarr-labs/homarr/commit/be1a26a98d2ed9d25969ded5ae64705c001f71dd))
## [1.53.0](https://github.com/homarr-labs/homarr/compare/v1.52.0...v1.53.0) (2026-02-06)
### Features
* **analytics:** consolidate server analytics into single comprehensive Umami event ([#4938](https://github.com/homarr-labs/homarr/issues/4938)) ([10848db](https://github.com/homarr-labs/homarr/commit/10848db595b2254b1485ea168d1c327b907d9ff8))
### Bug Fixes
* **deps:** update dependency @next/eslint-plugin-next to v16.1.5 ([#4959](https://github.com/homarr-labs/homarr/issues/4959)) ([ec40309](https://github.com/homarr-labs/homarr/commit/ec40309cde2280cf689856d4f78fb1500b583130))
* **deps:** update dependency @paralleldrive/cuid2 to ^3.3.0 ([#4952](https://github.com/homarr-labs/homarr/issues/4952)) ([a9db68b](https://github.com/homarr-labs/homarr/commit/a9db68bd3eaea6a4564cd6842054ea60cc45e3a3))
* **deps:** update dependency @tanstack/react-query-devtools to ^5.91.3 ([#4985](https://github.com/homarr-labs/homarr/issues/4985)) ([1115ad1](https://github.com/homarr-labs/homarr/commit/1115ad1364bca84dee33aa42499c986bdad2c528))
* **deps:** update dependency fast-xml-parser to ^5.3.4 ([#4982](https://github.com/homarr-labs/homarr/issues/4982)) ([460d53c](https://github.com/homarr-labs/homarr/commit/460d53cafa1abeebf4dea7b1bb1e920267c2f9fe))
* **deps:** update dependency fastify to ^5.7.2 ([#4955](https://github.com/homarr-labs/homarr/issues/4955)) ([0eab26c](https://github.com/homarr-labs/homarr/commit/0eab26cdace47c0b19519372a3daa6998e0c8207))
* **deps:** update dependency jotai to ^2.17.0 ([#4972](https://github.com/homarr-labs/homarr/issues/4972)) ([e67483f](https://github.com/homarr-labs/homarr/commit/e67483fea56f0b06fa54e68b8dd62fd0b5dedadd))
* **deps:** update dependency ldapts to v8.1.4 ([#4993](https://github.com/homarr-labs/homarr/issues/4993)) ([c2d9f18](https://github.com/homarr-labs/homarr/commit/c2d9f18e4ef28f063e4abf1175cd90ba746410b7))
* **deps:** update dependency mysql2 to v3.16.2 ([#4961](https://github.com/homarr-labs/homarr/issues/4961)) ([5c6eafb](https://github.com/homarr-labs/homarr/commit/5c6eafb272436b78d4668d562d50001bca48e6d3))
* **deps:** update dependency next-intl to v4.8.0 ([#4977](https://github.com/homarr-labs/homarr/issues/4977)) ([c3a7ab5](https://github.com/homarr-labs/homarr/commit/c3a7ab52ee3acbcf47255d5813317c3cf67ea49f))
* **deps:** update dependency next-intl to v4.8.1 ([#4986](https://github.com/homarr-labs/homarr/issues/4986)) ([62b6939](https://github.com/homarr-labs/homarr/commit/62b6939b92f29618cc6d13a189b65df1922779ba))
* **deps:** update dependency pg to ^8.18.0 ([#4989](https://github.com/homarr-labs/homarr/issues/4989)) ([c3071a3](https://github.com/homarr-labs/homarr/commit/c3071a3c95f3a30438050aa37c65950cccabf681))
* **deps:** update dependency typescript-eslint to ^8.54.0 ([#4958](https://github.com/homarr-labs/homarr/issues/4958)) ([e88d126](https://github.com/homarr-labs/homarr/commit/e88d126355b96ac5060b552047c191f8b284461c))
* **deps:** update dependency video.js to ^8.23.6 ([#4992](https://github.com/homarr-labs/homarr/issues/4992)) ([4209f7c](https://github.com/homarr-labs/homarr/commit/4209f7c70e75870f56b93a97f3b6053962ee3ff7))
* **deps:** update mantine monorepo to ^8.3.14 ([#4998](https://github.com/homarr-labs/homarr/issues/4998)) ([0fafa50](https://github.com/homarr-labs/homarr/commit/0fafa505ac1c7f4ddb33ee5e8dedca9a883164ba))
* **deps:** update nextjs monorepo to v16.1.6 ([#4969](https://github.com/homarr-labs/homarr/issues/4969)) ([7c3fe3d](https://github.com/homarr-labs/homarr/commit/7c3fe3d6d47879c67950b3dc4d7e39adbc06c146))
* **deps:** update react monorepo to v19.2.4 ([#4960](https://github.com/homarr-labs/homarr/issues/4960)) ([d3e0b47](https://github.com/homarr-labs/homarr/commit/d3e0b47875998fc766e1c5f0481244fc659b0c49))
* **deps:** update tiptap monorepo to v3.18.0 ([#4975](https://github.com/homarr-labs/homarr/issues/4975)) ([24e24dc](https://github.com/homarr-labs/homarr/commit/24e24dc634a9e5a25ab934541225996e62ac31be))
* **deps:** update trpc monorepo to ^11.9.0 ([#4970](https://github.com/homarr-labs/homarr/issues/4970)) ([aeb6e0f](https://github.com/homarr-labs/homarr/commit/aeb6e0f40659bf1c514380a6c96858afdaf7e6db))
* **deps:** update turbo monorepo to ^2.8.0 ([#4978](https://github.com/homarr-labs/homarr/issues/4978)) ([054ca57](https://github.com/homarr-labs/homarr/commit/054ca57188656ddac7aaa16f792269eaa2ef319b))
* **deps:** update turbo monorepo to ^2.8.1 ([#4991](https://github.com/homarr-labs/homarr/issues/4991)) ([43b6246](https://github.com/homarr-labs/homarr/commit/43b6246876debccbe7239c8ee67753e17527e469))
## [1.52.0](https://github.com/homarr-labs/homarr/compare/v1.51.0...v1.52.0) (2026-01-30)
### Features
* **installations:** support docker secrets file for encryption key ([#4946](https://github.com/homarr-labs/homarr/issues/4946)) ([9ba8213](https://github.com/homarr-labs/homarr/commit/9ba82133da2ae472952358f84d8ee1758c0f108a))
### Bug Fixes
* **deps:** update dependency @tanstack/react-query to ^5.90.20 ([#4939](https://github.com/homarr-labs/homarr/issues/4939)) ([840940b](https://github.com/homarr-labs/homarr/commit/840940bab663e728b8516ac48f913fef2b5c61b7))
* **deps:** update dependency next to v16.1.5 [security] ([#4937](https://github.com/homarr-labs/homarr/issues/4937)) ([aeb1df1](https://github.com/homarr-labs/homarr/commit/aeb1df122926c7bed71bea9b21f1c42c45cc9b3e))
* **deps:** update dependency pg to ^8.17.2 ([#4916](https://github.com/homarr-labs/homarr/issues/4916)) ([a50a29a](https://github.com/homarr-labs/homarr/commit/a50a29a778689efcca0afc2b640fdb497e6e7d98))
* **deps:** update dependency prettier to ^3.8.1 ([#4925](https://github.com/homarr-labs/homarr/issues/4925)) ([a727b8e](https://github.com/homarr-labs/homarr/commit/a727b8e323b9fb7cba536909a51fabde0a992a69))
* **deps:** update dependency sass to ^1.97.3 ([#4927](https://github.com/homarr-labs/homarr/issues/4927)) ([b1658a5](https://github.com/homarr-labs/homarr/commit/b1658a5d01b5c12f391af9d326ec98b3da000f9e))
* **deps:** update dependency typescript-eslint to ^8.53.1 ([#4904](https://github.com/homarr-labs/homarr/issues/4904)) ([c58da00](https://github.com/homarr-labs/homarr/commit/c58da0095738352515d6d8c5e81b3c34c8726ffe))
* **deps:** update mantine monorepo to ^8.3.13 ([#4911](https://github.com/homarr-labs/homarr/issues/4911)) ([f2eec74](https://github.com/homarr-labs/homarr/commit/f2eec748494480e773b45a309aa89ae3862e2b05))
* **deps:** update nextjs monorepo to v16.1.4 ([#4909](https://github.com/homarr-labs/homarr/issues/4909)) ([99a2574](https://github.com/homarr-labs/homarr/commit/99a2574d80ad5a7dfe3b9c92d43bd4b9423bf22d))
* **deps:** update tiptap monorepo to v3.16.0 ([#4912](https://github.com/homarr-labs/homarr/issues/4912)) ([2354510](https://github.com/homarr-labs/homarr/commit/23545101b61e456fd886eedb4b3d86b8cc606639))
* **deps:** update tiptap monorepo to v3.17.0 ([#4940](https://github.com/homarr-labs/homarr/issues/4940)) ([d030261](https://github.com/homarr-labs/homarr/commit/d03026187cb6451d727167b02ac138f9c7ccc754))
* **deps:** update tiptap monorepo to v3.17.1 ([#4945](https://github.com/homarr-labs/homarr/issues/4945)) ([b354085](https://github.com/homarr-labs/homarr/commit/b354085c7adfb6e5f3cad51b5b825426e072e874))
* **deps:** update turbo monorepo to ^2.7.6 ([#4947](https://github.com/homarr-labs/homarr/issues/4947)) ([e078237](https://github.com/homarr-labs/homarr/commit/e078237e31d11029987c6c4370fd8f65023b87bc))
## [1.51.0](https://github.com/homarr-labs/homarr/compare/v1.50.1...v1.51.0) (2026-01-23)
### Features
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:24.13.0-alpine AS base
FROM node:24.13.1-alpine AS base
FROM base AS builder
RUN apk add --no-cache libc6-compat
+28 -28
View File
@@ -48,21 +48,21 @@
"@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"@homarr/widgets": "workspace:^0.1.0",
"@mantine/colors-generator": "^8.3.12",
"@mantine/core": "^8.3.12",
"@mantine/dropzone": "^8.3.12",
"@mantine/hooks": "^8.3.12",
"@mantine/modals": "^8.3.12",
"@mantine/tiptap": "^8.3.12",
"@mantine/colors-generator": "^8.3.15",
"@mantine/core": "^8.3.15",
"@mantine/dropzone": "^8.3.15",
"@mantine/hooks": "^8.3.15",
"@mantine/modals": "^8.3.15",
"@mantine/tiptap": "^8.3.15",
"@million/lint": "1.0.14",
"@tabler/icons-react": "^3.36.1",
"@tanstack/react-query": "^5.90.19",
"@tanstack/react-query-devtools": "^5.91.2",
"@tabler/icons-react": "^3.37.1",
"@tanstack/react-query": "^5.90.21",
"@tanstack/react-query-devtools": "^5.91.3",
"@tanstack/react-query-next-experimental": "^5.91.0",
"@trpc/client": "^11.8.1",
"@trpc/next": "^11.8.1",
"@trpc/react-query": "^11.8.1",
"@trpc/server": "^11.8.1",
"@trpc/client": "^11.10.0",
"@trpc/next": "^11.10.0",
"@trpc/react-query": "^11.10.0",
"@trpc/server": "^11.10.0",
"@xterm/addon-canvas": "^0.7.0",
"@xterm/addon-fit": "0.11.0",
"@xterm/xterm": "^6.0.0",
@@ -70,22 +70,22 @@
"chroma-js": "^3.2.0",
"clsx": "^2.1.1",
"dayjs": "^1.11.19",
"dotenv": "^17.2.3",
"dotenv": "^17.3.1",
"flag-icons": "^7.5.0",
"glob": "^13.0.0",
"isomorphic-dompurify": "^2.35.0",
"jotai": "^2.16.2",
"glob": "^13.0.6",
"isomorphic-dompurify": "^3.0.0",
"jotai": "^2.18.0",
"mantine-react-table": "2.0.0-beta.9",
"next": "16.1.3",
"next": "16.1.6",
"postcss-preset-mantine": "^1.18.0",
"prismjs": "^1.30.0",
"react": "19.2.3",
"react-dom": "19.2.3",
"react-error-boundary": "^6.1.0",
"react": "19.2.4",
"react-dom": "19.2.4",
"react-error-boundary": "^6.1.1",
"react-simple-code-editor": "^0.14.1",
"sass": "^1.97.2",
"sass": "^1.97.3",
"superjson": "2.2.6",
"swagger-ui-react": "^5.31.0",
"swagger-ui-react": "^5.31.2",
"use-deep-compare-effect": "^1.8.1",
"zod": "^4.2.1"
},
@@ -94,15 +94,15 @@
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"@types/chroma-js": "3.1.2",
"@types/node": "^24.10.9",
"@types/prismjs": "^1.26.5",
"@types/react": "19.2.8",
"@types/node": "^24.10.13",
"@types/prismjs": "^1.26.6",
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3",
"@types/swagger-ui-react": "^5.18.0",
"concurrently": "^9.2.1",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"node-loader": "^2.1.0",
"prettier": "^3.8.0",
"prettier": "^3.8.1",
"typescript": "^5.9.3"
}
}
@@ -1,6 +1,5 @@
"use client";
import { startTransition } from "react";
import { Button, Card, Group, Stack, Switch, Text } from "@mantine/core";
import { IconArrowRight } from "@tabler/icons-react";
import type { z } from "zod/v4";
@@ -24,16 +23,6 @@ export const InitSettings = () => {
});
const form = useZodForm(settingsInitSchema, { initialValues: defaultServerSettings });
form.watch("analytics.enableGeneral", ({ value }) => {
if (!value) {
startTransition(() => {
form.setFieldValue("analytics.enableWidgetData", false);
form.setFieldValue("analytics.enableIntegrationData", false);
form.setFieldValue("analytics.enableUserData", false);
});
}
});
const handleSubmitAsync = async (values: z.infer<typeof settingsInitSchema>) => {
await mutateAsync(values);
};
@@ -47,24 +36,6 @@ export const InitSettings = () => {
<Stack gap="xs">
<AnalyticsRow kind="general" {...form.getInputProps("analytics.enableGeneral", { type: "checkbox" })} />
<Stack gap="xs" ps="md" w="100%">
<AnalyticsRow
kind="integrationData"
disabled={!form.values.analytics.enableGeneral}
{...form.getInputProps("analytics.enableWidgetData", { type: "checkbox" })}
/>
<AnalyticsRow
kind="widgetData"
disabled={!form.values.analytics.enableGeneral}
{...form.getInputProps("analytics.enableIntegrationData", { type: "checkbox" })}
/>
<AnalyticsRow
kind="usersData"
disabled={!form.values.analytics.enableGeneral}
{...form.getInputProps("analytics.enableUserData", { type: "checkbox" })}
/>
</Stack>
</Stack>
</Stack>
</Card>
@@ -24,15 +24,6 @@ export const AnalyticsSettings = ({ initialData }: AnalyticsSettingsProps) => {
return;
}
if (
!updatedValues.enableGeneral &&
(updatedValues.enableWidgetData || updatedValues.enableIntegrationData || updatedValues.enableUserData)
) {
updatedValues.enableIntegrationData = false;
updatedValues.enableUserData = false;
updatedValues.enableWidgetData = false;
}
void mutateAsync({
settingsKey: "analytics",
value: updatedValues,
@@ -54,30 +45,6 @@ export const AnalyticsSettings = ({ initialData }: AnalyticsSettingsProps) => {
<LoadingOverlay visible={isPending} zIndex={1000} overlayProps={{ radius: "sm", blur: 2 }} />
<Stack>
<SwitchSetting form={form} formKey="enableGeneral" title={t("general.title")} text={t("general.text")} />
<SwitchSetting
form={form}
formKey="enableIntegrationData"
ms="xl"
title={t("integrationData.title")}
text={t("integrationData.text")}
disabled={!form.values.enableGeneral}
/>
<SwitchSetting
form={form}
formKey="enableWidgetData"
ms="xl"
title={t("widgetData.title")}
text={t("widgetData.text")}
disabled={!form.values.enableGeneral}
/>
<SwitchSetting
form={form}
formKey="enableUserData"
ms="xl"
title={t("usersData.title")}
text={t("usersData.text")}
disabled={!form.values.enableGeneral}
/>
</Stack>
</Card>
</>
@@ -117,6 +117,8 @@ const createColumns = (
header: tTasks("field.interval.label"),
size: 200,
Cell({ row }) {
if (row.original.preventCustomInterval) return null;
const handleIntervalChange = (newCron: string | null) => {
if (!newCron || newCron === row.original.cron) return;
@@ -14,16 +14,22 @@ import type { SectionItem } from "~/app/[locale]/boards/_types";
import { useSectionContext } from "../sections/section-context";
import { useItemActions } from "./item-actions";
import { ItemMoveModal } from "./item-move-modal";
import { useSession } from "@homarr/auth/client";
export const BoardItemMenu = ({
offset,
item,
resetErrorBoundary,
}: {
offset: number;
interface BoardItemMenuProps {
offset: number;
item: SectionItem;
resetErrorBoundary?: () => void;
}) => {
}
export const BoardItemMenu = (props: BoardItemMenuProps) => {
const {data: session} = useSession();
if (!session) return null;
return <BoardItemMenuInner {...props} />;
};
const BoardItemMenuInner = ({ offset, item, resetErrorBoundary }: BoardItemMenuProps) => {
const refResetErrorBoundaryOnNextRender = useRef(false);
const tItem = useScopedI18n("item");
const t = useI18n();
@@ -130,4 +136,4 @@ export const BoardItemMenu = ({
</Menu.Dropdown>
</Menu>
);
};
}
@@ -58,6 +58,7 @@ export const useCategoryActions = () => {
...section,
yOffset: section.yOffset + 2,
})),
...previous.sections.filter((section) => section.kind !== "category" && section.kind !== "empty"),
] satisfies Section[],
}));
},
+6 -6
View File
@@ -38,8 +38,8 @@
"@homarr/validation": "workspace:^0.1.0",
"@homarr/widgets": "workspace:^0.1.0",
"dayjs": "^1.11.19",
"dotenv": "^17.2.3",
"fastify": "^5.7.1",
"dotenv": "^17.3.1",
"fastify": "^5.7.4",
"superjson": "2.2.6",
"undici": "7.18.2"
},
@@ -47,11 +47,11 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"@types/node": "^24.10.9",
"@types/node": "^24.10.13",
"dotenv-cli": "^11.0.0",
"esbuild": "^0.27.2",
"eslint": "^9.39.2",
"prettier": "^3.8.0",
"esbuild": "^0.27.3",
"eslint": "^9.39.3",
"prettier": "^3.8.1",
"tsx": "4.20.4",
"typescript": "^5.9.3"
}
+12 -1
View File
@@ -31,6 +31,10 @@ export class JobManager implements IJobManager {
if (!validateCron(cron)) {
throw new Error(`Invalid cron expression: ${cron}`);
}
if (job.preventCustomInterval && cron !== job.cronExpression) {
throw new Error(`Custom cron expressions are not allowed for job ${name}`);
}
await this.updateConfigurationAsync(name, { cronExpression: cron });
await this.jobGroup.getTask(name)?.destroy();
@@ -100,7 +104,13 @@ export class JobManager implements IJobManager {
}
public async getAllAsync(): Promise<
{ name: JobGroupKeys; cron: string; preventManualExecution: boolean; isEnabled: boolean }[]
{
name: JobGroupKeys;
cron: string;
preventManualExecution: boolean;
preventCustomInterval: boolean;
isEnabled: boolean;
}[]
> {
const configurations = await this.db.query.cronJobConfigurations.findMany();
@@ -110,6 +120,7 @@ export class JobManager implements IJobManager {
name,
cron: config?.cronExpression ?? job.cronExpression,
preventManualExecution: job.preventManualExecution,
preventCustomInterval: job.preventCustomInterval,
isEnabled: config?.isEnabled ?? true,
};
});
+4 -4
View File
@@ -25,7 +25,7 @@
"@homarr/definitions": "workspace:^0.1.0",
"@homarr/redis": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"dotenv": "^17.2.3",
"dotenv": "^17.3.1",
"tsx": "4.20.4",
"ws": "^8.19.0"
},
@@ -34,9 +34,9 @@
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"@types/ws": "^8.18.1",
"esbuild": "^0.27.2",
"eslint": "^9.39.2",
"prettier": "^3.8.0",
"esbuild": "^0.27.3",
"eslint": "^9.39.3",
"prettier": "^3.8.1",
"typescript": "^5.9.3"
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:24.13.0-trixie AS base
FROM node:24.13.1-trixie AS base
WORKDIR /app
COPY package.json .
COPY pnpm-lock.yaml .
+3 -3
View File
@@ -4,10 +4,10 @@
"dependencies": {
"better-sqlite3": "^12.6.2"
},
"packageManager": "pnpm@10.28.0",
"packageManager": "pnpm@10.30.1",
"engines": {
"node": ">=24.13.0",
"pnpm": ">=10.28.0"
"node": ">=24.13.1",
"pnpm": ">=10.30.1"
},
"pnpm": {
"onlyBuiltDependencies": [
+28 -14
View File
@@ -134,6 +134,13 @@
</a>
</td>
<td align="center">
<a href="null" target="_blank" rel="noreferrer noopener">
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/glances.svg" alt="Glances" width="90" height="90" />
<br/>
<p align="center">Glances</p>
</a>
</td>
<td align="center">
<a href="https://homarr.dev/docs/integrations/home-assistant" target="_blank" rel="noreferrer noopener">
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/home-assistant.svg" alt="Home Assistant" width="90" height="90" />
<br/>
@@ -146,15 +153,15 @@
<br/>
<p align="center">iCal</p>
</a>
</td>
<td align="center">
</td></tr>
<tr><td align="center">
<a href="https://homarr.dev/docs/integrations/jellyfin" target="_blank" rel="noreferrer noopener">
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/jellyfin.svg" alt="Jellyfin" width="90" height="90" />
<br/>
<p align="center">Jellyfin</p>
</a>
</td></tr>
<tr><td align="center">
</td>
<td align="center">
<a href="https://homarr.dev/docs/integrations/jellyseerr" target="_blank" rel="noreferrer noopener">
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/jellyseerr.svg" alt="Jellyseerr" width="90" height="90" />
<br/>
@@ -195,15 +202,15 @@
<br/>
<p align="center">ntfy</p>
</a>
</td>
<td align="center">
</td></tr>
<tr><td align="center">
<a href="https://homarr.dev/docs/integrations/nzbget" target="_blank" rel="noreferrer noopener">
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/nzbget.svg" alt="NZBGet" width="90" height="90" />
<br/>
<p align="center">NZBGet</p>
</a>
</td></tr>
<tr><td align="center">
</td>
<td align="center">
<a href="https://homarr.dev/docs/integrations/open-media-vault" target="_blank" rel="noreferrer noopener">
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/openmediavault.svg" alt="OpenMediaVault" width="90" height="90" />
<br/>
@@ -244,15 +251,15 @@
<br/>
<p align="center">Prowlarr</p>
</a>
</td>
<td align="center">
</td></tr>
<tr><td align="center">
<a href="https://homarr.dev/docs/integrations/proxmox" target="_blank" rel="noreferrer noopener">
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/proxmox.svg" alt="Proxmox" width="90" height="90" />
<br/>
<p align="center">Proxmox</p>
</a>
</td></tr>
<tr><td align="center">
</td>
<td align="center">
<a href="https://homarr.dev/docs/integrations/q-bittorent" target="_blank" rel="noreferrer noopener">
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/qbittorrent.svg" alt="qBittorrent" width="90" height="90" />
<br/>
@@ -288,6 +295,13 @@
</a>
</td>
<td align="center">
<a href="https://homarr.dev/docs/integrations/slskd" target="_blank" rel="noreferrer noopener">
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/slskd.svg" alt="Slskd" width="90" height="90" />
<br/>
<p align="center">Slskd</p>
</a>
</td></tr>
<tr><td align="center">
<a href="https://homarr.dev/docs/integrations/sonarr" target="_blank" rel="noreferrer noopener">
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/sonarr.svg" alt="Sonarr" width="90" height="90" />
<br/>
@@ -300,8 +314,8 @@
<br/>
<p align="center">Tdarr</p>
</a>
</td></tr>
<tr><td align="center">
</td>
<td align="center">
<a href="https://homarr.dev/docs/integrations/transmission" target="_blank" rel="noreferrer noopener">
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/transmission.svg" alt="Transmission" width="90" height="90" />
<br/>
+25 -25
View File
@@ -1,6 +1,6 @@
{
"name": "homarr",
"version": "1.51.0",
"version": "1.54.0",
"private": true,
"scripts": {
"build": "cross-env CI=true turbo build",
@@ -39,30 +39,30 @@
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/commit-analyzer": "^13.0.1",
"@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^12.0.2",
"@semantic-release/npm": "^13.1.3",
"@semantic-release/github": "^12.0.6",
"@semantic-release/npm": "^13.1.4",
"@semantic-release/release-notes-generator": "^14.1.0",
"@testcontainers/redis": "^11.11.0",
"@turbo/gen": "^2.7.5",
"@vitejs/plugin-react": "^5.1.2",
"@vitest/coverage-v8": "^4.0.17",
"@vitest/ui": "^4.0.17",
"@testcontainers/redis": "^11.12.0",
"@turbo/gen": "^2.8.9",
"@vitejs/plugin-react": "^5.1.4",
"@vitest/coverage-v8": "^4.0.18",
"@vitest/ui": "^4.0.18",
"conventional-changelog-conventionalcommits": "^9.1.0",
"cross-env": "^10.1.0",
"jsdom": "^27.4.0",
"jsdom": "^28.1.0",
"json5": "^2.2.3",
"prettier": "^3.8.0",
"semantic-release": "^25.0.2",
"testcontainers": "^11.11.0",
"turbo": "^2.7.5",
"prettier": "^3.8.1",
"semantic-release": "^25.0.3",
"testcontainers": "^11.12.0",
"turbo": "^2.8.9",
"typescript": "^5.9.3",
"vite-tsconfig-paths": "^6.0.4",
"vitest": "^4.0.17"
"vite-tsconfig-paths": "^6.1.1",
"vitest": "^4.0.18"
},
"packageManager": "pnpm@10.28.0",
"packageManager": "pnpm@10.30.1",
"engines": {
"node": ">=24.13.0",
"pnpm": ">=10.28.0"
"node": ">=24.13.1",
"pnpm": ">=10.30.1"
},
"pnpm": {
"onlyBuiltDependencies": [
@@ -79,18 +79,18 @@
"overrides": {
"@babel/helpers@<7.26.10": ">=7.28.6",
"@babel/runtime@<7.26.10": ">=7.28.6",
"axios@>=1.0.0 <1.8.2": ">=1.13.2",
"brace-expansion@>=2.0.0 <=2.0.1": ">=4.0.1",
"axios@>=1.0.0 <1.8.2": ">=1.13.5",
"brace-expansion@>=2.0.0 <=2.0.1": ">=5.0.3",
"brace-expansion@>=1.0.0 <=1.1.11": ">=4.0.1",
"esbuild@<=0.24.2": ">=0.27.2",
"esbuild@<=0.24.2": ">=0.27.3",
"form-data@>=4.0.0 <4.0.4": ">=4.0.5",
"hono@<4.6.5": ">=4.11.4",
"hono@<4.6.5": ">=4.11.9",
"linkifyjs@<4.3.2": ">=4.3.2",
"nanoid@>=4.0.0 <5.0.9": ">=5.1.6",
"prismjs@<1.30.0": ">=1.30.0",
"proxmox-api>undici": "7.18.2",
"react-is": "^19.2.3",
"rollup@>=4.0.0 <4.22.4": ">=4.55.1",
"proxmox-api>undici": "7.19.2",
"react-is": "^19.2.4",
"rollup@>=4.0.0 <4.22.4": ">=4.59.0",
"sha.js@<=2.4.11": ">=2.4.12",
"tar-fs@>=3.0.0 <3.0.9": ">=3.1.1",
"tar-fs@>=2.0.0 <2.1.3": ">=3.1.1",
+4 -1
View File
@@ -22,8 +22,11 @@
},
"prettier": "@homarr/prettier-config",
"dependencies": {
"@homarr/auth": "workspace:^0.1.0",
"@homarr/common": "workspace:^0.1.0",
"@homarr/core": "workspace:^0.1.0",
"@homarr/db": "workspace:^0.1.0",
"@homarr/docker": "workspace:^0.1.0",
"@homarr/server-settings": "workspace:^0.1.0",
"@umami/node": "^0.4.0",
"superjson": "2.2.6"
@@ -32,7 +35,7 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+70 -54
View File
@@ -1,17 +1,52 @@
import type { UmamiEventData } from "@umami/node";
import { Umami } from "@umami/node";
import { isProviderEnabled } from "@homarr/auth/server";
import { Stopwatch } from "@homarr/common";
import { createLogger } from "@homarr/core/infrastructure/logs";
import { count, db } from "@homarr/db";
import { isMysql, isPostgresql } from "@homarr/db/collection";
import { getServerSettingByKeyAsync } from "@homarr/db/queries";
import { integrations, items, users } from "@homarr/db/schema";
import type { defaultServerSettings } from "@homarr/server-settings";
import {
apiKeys,
apps,
boards,
cronJobConfigurations,
groups,
iconRepositories,
icons,
integrations,
invites,
itemLayouts,
items,
layouts,
medias,
searchEngines,
sectionLayouts,
sections,
users,
} from "@homarr/db/schema";
import { env as dockerEnv } from "@homarr/docker/env";
import { Stopwatch } from "../../common/src";
import packageJson from "../../../package.json";
import { UMAMI_HOST_URL, UMAMI_WEBSITE_ID } from "./constants";
const logger = createLogger({ module: "analytics" });
const getDatabaseType = (): "mysql" | "postgresql" | "sqlite" => {
if (isMysql()) return "mysql";
if (isPostgresql()) return "postgresql";
return "sqlite";
};
const getEnabledAuthProviders = (): string[] => {
const providers: string[] = [];
if (isProviderEnabled("credentials")) providers.push("credentials");
if (isProviderEnabled("oidc")) providers.push("oidc");
if (isProviderEnabled("ldap")) providers.push("ldap");
return providers;
};
export const sendServerAnalyticsAsync = async () => {
const stopWatch = new Stopwatch();
const analyticsSettings = await getServerSettingByKeyAsync(db, "analytics");
@@ -27,67 +62,48 @@ export const sendServerAnalyticsAsync = async () => {
websiteId: UMAMI_WEBSITE_ID,
});
await sendIntegrationDataAsync(umamiInstance, analyticsSettings);
await sendWidgetDataAsync(umamiInstance, analyticsSettings);
await sendUserDataAsync(umamiInstance, analyticsSettings);
const enabledAuthProviders = getEnabledAuthProviders();
logger.info(`Sent all analytics in ${stopWatch.getElapsedInHumanWords()}`);
};
const analyticsData: UmamiEventData = {
homarrVersion: packageJson.version,
databaseType: getDatabaseType(),
dockerEnabled: dockerEnv.ENABLE_DOCKER ? 1 : 0,
kubernetesEnabled: dockerEnv.ENABLE_KUBERNETES ? 1 : 0,
authCredentials: enabledAuthProviders.includes("credentials") ? 1 : 0,
authOidc: enabledAuthProviders.includes("oidc") ? 1 : 0,
authLdap: enabledAuthProviders.includes("ldap") ? 1 : 0,
countUsers: await db.$count(users),
countBoards: await db.$count(boards),
countGroups: await db.$count(groups),
countApps: await db.$count(apps),
countWidgets: await db.$count(items),
countSections: await db.$count(sections),
countIntegrations: await db.$count(integrations),
countSearchEngines: await db.$count(searchEngines),
countIconRepositories: await db.$count(iconRepositories),
countIcons: await db.$count(icons),
countApiKeys: await db.$count(apiKeys),
countInvites: await db.$count(invites),
countMedias: await db.$count(medias),
countLayouts: await db.$count(layouts),
countItemLayouts: await db.$count(itemLayouts),
countSectionLayouts: await db.$count(sectionLayouts),
countCronJobConfigs: await db.$count(cronJobConfigurations),
};
const sendWidgetDataAsync = async (umamiInstance: Umami, analyticsSettings: typeof defaultServerSettings.analytics) => {
if (!analyticsSettings.enableWidgetData) {
return;
}
const widgetCount = await db.$count(items);
const response = await umamiInstance.track("server-widget-data", {
countWidgets: widgetCount,
});
if (response.ok) {
return;
}
logger.warn("Unable to send track event data to Umami instance");
};
const sendUserDataAsync = async (umamiInstance: Umami, analyticsSettings: typeof defaultServerSettings.analytics) => {
if (!analyticsSettings.enableUserData) {
return;
}
const userCount = await db.$count(users);
const response = await umamiInstance.track("server-user-data", {
countUsers: userCount,
});
if (response.ok) {
return;
}
logger.warn("Unable to send track event data to Umami instance");
};
const sendIntegrationDataAsync = async (
umamiInstance: Umami,
analyticsSettings: typeof defaultServerSettings.analytics,
) => {
if (!analyticsSettings.enableIntegrationData) {
return;
}
const integrationKinds = await db
.select({ kind: integrations.kind, count: count(integrations.id) })
.from(integrations)
.groupBy(integrations.kind);
const map: UmamiEventData = {};
integrationKinds.forEach((integrationKind) => {
map[integrationKind.kind] = integrationKind.count;
analyticsData[`integration_${integrationKind.kind}`] = integrationKind.count;
});
const response = await umamiInstance.track("server-integration-data-kind", map);
if (response.ok) {
return;
const response = await umamiInstance.track("server-analytics-v2", analyticsData);
if (!response.ok) {
logger.warn("Unable to send analytics to Umami instance");
}
logger.warn("Unable to send track event data to Umami instance");
logger.info(`Sent analytics in ${stopWatch.getElapsedInHumanWords()}`);
};
+10 -10
View File
@@ -41,15 +41,15 @@
"@homarr/translation": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"@kubernetes/client-node": "^1.4.0",
"@tanstack/react-query": "^5.90.19",
"@trpc/client": "^11.8.1",
"@trpc/react-query": "^11.8.1",
"@trpc/server": "^11.8.1",
"@trpc/tanstack-react-query": "^11.8.1",
"@tanstack/react-query": "^5.90.21",
"@trpc/client": "^11.10.0",
"@trpc/react-query": "^11.10.0",
"@trpc/server": "^11.10.0",
"@trpc/tanstack-react-query": "^11.10.0",
"lodash.clonedeep": "^4.5.0",
"next": "16.1.3",
"react": "19.2.3",
"react-dom": "19.2.3",
"next": "16.1.6",
"react": "19.2.4",
"react-dom": "19.2.4",
"superjson": "2.2.6",
"trpc-to-openapi": "^3.1.0",
"zod": "^4.2.1"
@@ -58,8 +58,8 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"prettier": "^3.8.0",
"eslint": "^9.39.3",
"prettier": "^3.8.1",
"typescript": "^5.9.3"
}
}
+34 -15
View File
@@ -1,7 +1,9 @@
import { TRPCError } from "@trpc/server";
import { z } from "zod/v4";
import type { Session } from "@homarr/auth";
import { createId } from "@homarr/common";
import type { Database, InferSelectModel } from "@homarr/db";
import { asc, eq, inArray, like } from "@homarr/db";
import { apps } from "@homarr/db/schema";
import { selectAppSchema } from "@homarr/db/validationSchemas";
@@ -11,7 +13,7 @@ import { byIdSchema, paginatedSchema } from "@homarr/validation/common";
import { convertIntersectionToZodObject } from "../schema-merger";
import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../trpc";
import { canUserSeeAppAsync } from "./app/app-access-control";
import { AppAccessControl } from "./app/app-access-control";
const defaultIcon = "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/homarr.svg";
@@ -89,9 +91,8 @@ export const appRouter = createTRPCRouter({
.output(selectAppSchema)
.meta({ openapi: { method: "GET", path: "/api/apps/{id}", tags: ["apps"], protect: true } })
.query(async ({ ctx, input }) => {
const app = await ctx.db.query.apps.findFirst({
where: eq(apps.id, input.id),
});
const repository = new AppRepository(ctx.db, ctx.session?.user ?? null);
const app = await repository.getByIdAsync(input.id);
if (!app) {
throw new TRPCError({
@@ -100,20 +101,11 @@ export const appRouter = createTRPCRouter({
});
}
const canUserSeeApp = await canUserSeeAppAsync(ctx.session?.user ?? null, app.id);
if (!canUserSeeApp) {
throw new TRPCError({
code: "NOT_FOUND",
message: "App not found",
});
}
return app;
}),
byIds: publicProcedure.input(z.array(z.string())).query(async ({ ctx, input }) => {
return await ctx.db.query.apps.findMany({
where: inArray(apps.id, input),
});
const repository = new AppRepository(ctx.db, ctx.session?.user ?? null);
return await repository.getByIdsAsync(input);
}),
create: permissionRequiredProcedure
.requiresPermission("app-create")
@@ -187,3 +179,30 @@ export const appRouter = createTRPCRouter({
await ctx.db.delete(apps).where(eq(apps.id, input.id));
}),
});
type App = InferSelectModel<typeof apps>;
export class AppRepository {
private readonly accessControl: AppAccessControl;
constructor(
private db: Database,
user: Session["user"] | null,
) {
this.accessControl = new AppAccessControl(db, user);
}
public async getByIdAsync(id: string): Promise<App | null> {
const apps = await this.getByIdsAsync([id]);
return apps[0] ?? null;
}
public async getByIdsAsync(ids: string[]): Promise<App[]> {
const canUserSeeApps = await this.accessControl.canUserSeeAppsAsync(ids);
const dbApps = await this.db.query.apps.findMany({
where: inArray(apps.id, ids),
});
return canUserSeeApps ? dbApps : [];
}
}
@@ -1,45 +1,52 @@
import SuperJSON from "superjson";
import type { Session } from "@homarr/auth";
import { db, eq, or } from "@homarr/db";
import type { Database } from "@homarr/db";
import { eq, or } from "@homarr/db";
import { items } from "@homarr/db/schema";
import type { WidgetComponentProps } from "../../../../widgets/src";
export const canUserSeeAppAsync = async (user: Session["user"] | null, appId: string) => {
return await canUserSeeAppsAsync(user, [appId]);
};
export class AppAccessControl {
constructor(
private db: Database,
private user: Session["user"] | null,
) {}
export const canUserSeeAppsAsync = async (user: Session["user"] | null, appIds: string[]) => {
if (user) return true;
async canUserSeeAppAsync(appId: string) {
return await this.canUserSeeAppsAsync([appId]);
}
const appIdsOnPublicBoards = await getAllAppIdsOnPublicBoardsAsync();
return appIds.every((appId) => appIdsOnPublicBoards.includes(appId));
};
async canUserSeeAppsAsync(appIds: string[]) {
// Currently any user can see all apps if they are logged in
if (this.user) return true;
const getAllAppIdsOnPublicBoardsAsync = async () => {
const itemsWithApps = await db.query.items.findMany({
where: or(eq(items.kind, "app"), eq(items.kind, "bookmarks")),
with: {
board: {
columns: {
isPublic: true,
const appIdsOnPublicBoards = await this.getAllAppIdsOnPublicBoardsAsync();
return appIds.every((appId) => appIdsOnPublicBoards.includes(appId));
}
private async getAllAppIdsOnPublicBoardsAsync() {
const itemsWithApps = await this.db.query.items.findMany({
where: or(eq(items.kind, "app"), eq(items.kind, "bookmarks")),
with: {
board: {
columns: {
isPublic: true,
},
},
},
},
});
});
return itemsWithApps
.filter((item) => item.board.isPublic)
.flatMap((item) => {
if (item.kind === "app") {
const parsedOptions = SuperJSON.parse<WidgetComponentProps<"app">["options"]>(item.options);
return [parsedOptions.appId];
}
return itemsWithApps
.filter((item) => item.board.isPublic)
.flatMap((item) => {
if (item.kind === "app") {
const parsedOptions = SuperJSON.parse<WidgetComponentProps<"app">["options"]>(item.options);
return [parsedOptions.appId];
} else if (item.kind === "bookmarks") {
const parsedOptions = SuperJSON.parse<WidgetComponentProps<"bookmarks">["options"]>(item.options);
return parsedOptions.items;
}
throw new Error("Failed to get app ids from board. Invalid item kind: 'test'");
});
};
});
}
}
@@ -43,7 +43,7 @@ import { mapTestConnectionError } from "./map-test-connection-error";
const logger = createLogger({ module: "integrationRouter" });
export const integrationRouter = createTRPCRouter({
all: publicProcedure.query(async ({ ctx }) => {
all: protectedProcedure.query(async ({ ctx }) => {
const groupsOfCurrentUser = await ctx.db.query.groupMembers.findMany({
where: eq(groupMembers.userId, ctx.session?.user.id ?? ""),
});
@@ -85,7 +85,7 @@ export const integrationRouter = createTRPCRouter({
integrationKinds.indexOf(integrationA.kind) - integrationKinds.indexOf(integrationB.kind),
);
}),
allThatSupportSearch: publicProcedure.query(async ({ ctx }) => {
allThatSupportSearch: protectedProcedure.query(async ({ ctx }) => {
const groupsOfCurrentUser = await ctx.db.query.groupMembers.findMany({
where: eq(groupMembers.userId, ctx.session?.user.id ?? ""),
});
@@ -133,7 +133,7 @@ export const integrationRouter = createTRPCRouter({
integrationKinds.indexOf(integrationA.kind) - integrationKinds.indexOf(integrationB.kind),
);
}),
allOfGivenCategory: publicProcedure
allOfGivenCategory: protectedProcedure
.input(
z.object({
category: z.enum(integrationCategories),
+10 -2
View File
@@ -13,6 +13,14 @@ import * as appAccessControl from "../app/app-access-control";
// Mock the auth module to return an empty session
vi.mock("@homarr/auth", () => ({ auth: () => ({}) as Session }));
const createFakeAccessControl = (canAccess: boolean) =>
vi.fn(
class {
canUserSeeAppAsync = async (_: string) => await Promise.resolve(canAccess);
canUserSeeAppsAsync = async (_: string[]) => await Promise.resolve(canAccess);
} as unknown as typeof appAccessControl.AppAccessControl,
);
const createDefaultSession = (permissions: GroupPermissionKey[] = []): Session => ({
user: { id: createId(), permissions, colorScheme: "light" },
expires: new Date().toISOString(),
@@ -77,7 +85,7 @@ describe("byId should return an app by id", () => {
deviceType: undefined,
session: null,
});
vi.spyOn(appAccessControl, "canUserSeeAppAsync").mockReturnValue(Promise.resolve(true));
vi.spyOn(appAccessControl, "AppAccessControl").mockImplementation(createFakeAccessControl(true));
await db.insert(apps).values([
{
@@ -118,7 +126,7 @@ describe("byId should return an app by id", () => {
href: "https://mantine.dev",
},
]);
vi.spyOn(appAccessControl, "canUserSeeAppAsync").mockReturnValue(Promise.resolve(false));
vi.spyOn(appAccessControl, "AppAccessControl").mockImplementation(createFakeAccessControl(false));
// Act
const actAsync = async () => await caller.byId({ id: "2" });
@@ -1,6 +1,9 @@
import { describe, expect, test, vi } from "vitest";
import type { Session } from "@homarr/auth";
import { createId } from "@homarr/common";
import type { InferInsertModel } from "@homarr/db";
import { apps } from "@homarr/db/schema";
import { createDb } from "@homarr/db/test";
import * as ping from "@homarr/ping";
@@ -9,22 +12,31 @@ import { appRouter } from "../../widgets/app";
// Mock the auth module to return an empty session
vi.mock("@homarr/auth", () => ({ auth: () => ({}) as Session }));
vi.mock("@homarr/ping", () => ({ sendPingRequestAsync: async () => await Promise.resolve(null) }));
vi.mock("../../app/app-access-control", () => ({
AppAccessControl: vi.fn(
class {
canUserSeeAppAsync = async (_: string) => await Promise.resolve(true);
canUserSeeAppsAsync = async (_: string[]) => await Promise.resolve(true);
},
),
}));
describe("ping should call sendPingRequestAsync with url and return result", () => {
test("ping with error response should return error and url", async () => {
// Arrange
const spy = vi.spyOn(ping, "sendPingRequestAsync");
vi.spyOn(ping, "sendPingRequestAsync").mockImplementation(() => Promise.resolve({ error: "error" }));
const url = "http://localhost";
const db = createDb();
const app = createApp({ url });
await db.insert(apps).values(app);
const caller = appRouter.createCaller({
db,
deviceType: undefined,
session: null,
});
spy.mockImplementation(() => Promise.resolve({ error: "error" }));
// Act
const result = await caller.ping({ url });
const result = await caller.ping({ id: app.id });
// Assert
expect(result.url).toBe(url);
@@ -33,21 +45,32 @@ describe("ping should call sendPingRequestAsync with url and return result", ()
test("ping with success response should return statusCode and url", async () => {
// Arrange
const spy = vi.spyOn(ping, "sendPingRequestAsync");
vi.spyOn(ping, "sendPingRequestAsync").mockImplementation(() =>
Promise.resolve({ statusCode: 200, durationMs: 123 }),
);
const url = "http://localhost";
const db = createDb();
const app = createApp({ url });
await db.insert(apps).values(app);
const caller = appRouter.createCaller({
db,
deviceType: undefined,
session: null,
});
spy.mockImplementation(() => Promise.resolve({ statusCode: 200, durationMs: 123 }));
// Act
const result = await caller.ping({ url });
const result = await caller.ping({ id: app.id });
// Assert
expect(result.url).toBe(url);
expect("statusCode" in result).toBe(true);
});
});
const createApp = ({ url }: { url: string }) =>
({
id: createId(),
iconUrl: "",
name: "Test App",
href: url,
}) satisfies InferInsertModel<typeof apps>;
@@ -0,0 +1,221 @@
import SuperJSON from "superjson";
import { describe, expect, test } from "vitest";
import type { Session } from "@homarr/auth";
import { createId } from "@homarr/common";
import type { InferInsertModel } from "@homarr/db";
import {
boardGroupPermissions,
boards,
boardUserPermissions,
groupMembers,
groups,
items,
users,
} from "@homarr/db/schema";
import { createDb } from "@homarr/db/test";
import type { GroupPermissionKey } from "@homarr/definitions";
import type { WidgetComponentProps } from "../../../../../widgets/src/definition";
import { canAccessAllFeedsAsync, restrictUrlsAsync } from "../../widgets/rssFeed";
const createSession = (permissions: GroupPermissionKey[] = []): Session => ({
user: {
id: "user-id",
colorScheme: "light",
permissions,
},
expires: new Date().toISOString(),
});
describe("rssFeedRouter", () => {
describe("canAccessAllFeedsAsync", () => {
test("should return false for unauthenticated users", async () => {
// Arrange
const { callback } = setupAccessCheck();
// Act
const result = await callback(/* session: */ null);
// Assert
expect(result).toBe(false);
});
test.each([["board-create" as const], ["board-modify-all" as const]])(
"should return true for users with %s permission",
async (permission) => {
// Arrange
const { callback } = setupAccessCheck();
const session = createSession([permission]);
// Act
const result = await callback(session);
// Assert
expect(result).toBe(true);
},
);
test("should return false for authenticated users without any boards or permissions", async () => {
// Arrange
const { callback, db } = setupAccessCheck();
const session = createSession();
await db.insert(users).values({
id: session.user.id,
});
// Act
const result = await callback(session);
// Assert
expect(result).toBe(false);
});
test("should return true for authenticated users that own at least one board", async () => {
// Arrange
const { callback, db } = setupAccessCheck();
const session = createSession();
await db.insert(users).values({
id: session.user.id,
});
await db.insert(boards).values({
id: createId(),
name: "test",
creatorId: session.user.id,
});
// Act
const result = await callback(session);
// Assert
expect(result).toBe(true);
});
test.each([["modify" as const], ["full" as const]])(
"should return true for authenticated users that have %s permissions on at least one board",
async (permission) => {
// Arrange
const { callback, db } = setupAccessCheck();
const session = createSession();
await db.insert(users).values({
id: session.user.id,
});
const boardId = createId();
await db.insert(boards).values({
id: boardId,
name: "test",
});
await db.insert(boardUserPermissions).values({
boardId,
permission,
userId: session.user.id,
});
// Act
const result = await callback(session);
// Assert
expect(result).toBe(true);
},
);
test.each([["modify" as const], ["full" as const]])(
"should return true for authenticated users that have %s permissions through group on at least one board",
async (permission) => {
// Arrange
const { callback, db } = setupAccessCheck();
const session = createSession();
await db.insert(users).values({
id: session.user.id,
});
const boardId = createId();
await db.insert(boards).values({
id: boardId,
name: "test",
});
const groupId = createId();
await db.insert(groups).values({
id: groupId,
name: "test-group",
position: 0,
});
await db.insert(groupMembers).values({
groupId,
userId: session.user.id,
});
await db.insert(boardGroupPermissions).values({
boardId,
groupId,
permission,
});
// Act
const result = await callback(session);
// Assert
expect(result).toBe(true);
},
);
});
describe("restrictUrlsAsync", () => {
test("should return empty array if there are no rss feed items in the database", async () => {
// Arrange
const { callback } = await setupUrlRestrictionAsync([]);
// Act
const result = await callback(["http://example.com/feed"]);
// Assert
expect(result).toEqual([]);
});
test("should return only the URLs that are present in the database", async () => {
// Arrange
const { callback } = await setupUrlRestrictionAsync(["http://example.com/feed"]);
// Act
const result = await callback(["http://example.com/feed", "http://not-in-db.com/feed"]);
// Assert
expect(result).toEqual(["http://example.com/feed"]);
});
});
});
function setupAccessCheck() {
const db = createDb();
return {
callback: (session: Session | null) => canAccessAllFeedsAsync(db, session),
db,
};
}
async function setupUrlRestrictionAsync(dbUrls: string[]) {
const db = createDb();
const boardId = createId();
await db.insert(boards).values({
id: boardId,
name: "test",
});
if (dbUrls.length >= 1) {
await db.insert(items).values(
dbUrls.map(
(url) =>
({
id: createId(),
kind: "rssFeed",
boardId,
options: SuperJSON.stringify({
feedUrls: [url],
enableRtl: false,
hideDescription: false,
textLinesClamp: 3,
maximumAmountPosts: 5,
} satisfies WidgetComponentProps<"rssFeed">["options"]),
}) satisfies InferInsertModel<typeof items>,
),
);
}
return {
callback: (urls: string[]) => restrictUrlsAsync(db, urls),
db,
};
}
+64 -10
View File
@@ -1,43 +1,97 @@
import { TRPCError } from "@trpc/server";
import { observable } from "@trpc/server/observable";
import { z } from "zod/v4";
import { getServerSettingByKeyAsync } from "@homarr/db/queries";
import { sendPingRequestAsync } from "@homarr/ping";
import { pingChannel, pingUrlChannel } from "@homarr/redis";
import { createTRPCRouter, publicProcedure } from "../../trpc";
import { AppRepository } from "../app";
export const appRouter = createTRPCRouter({
ping: publicProcedure.input(z.object({ url: z.string() })).query(async ({ input }) => {
const pingResult = await sendPingRequestAsync(input.url);
ping: publicProcedure.input(z.object({ id: z.string() })).query(async ({ ctx, input }) => {
const boardSettings = await getServerSettingByKeyAsync(ctx.db, "board");
if (boardSettings.forceDisableStatus) {
throw new TRPCError({
code: "FORBIDDEN",
message: "Ping functionality is disabled by server settings",
});
}
const repository = new AppRepository(ctx.db, ctx.session?.user ?? null);
const app = await repository.getByIdAsync(input.id);
if (!app) {
throw new TRPCError({
code: "NOT_FOUND",
message: "App not found",
});
}
const pingUrl = app.pingUrl ?? app.href;
if (!pingUrl) {
throw new TRPCError({
code: "CONFLICT",
message: "No URL to ping configured for this app",
});
}
const pingResult = await sendPingRequestAsync(pingUrl);
return {
url: input.url,
url: pingUrl,
...pingResult,
};
}),
updatedPing: publicProcedure
.input(
z.object({
url: z.string(),
id: z.string(),
}),
)
.subscription(async ({ input }) => {
await pingUrlChannel.addAsync(input.url);
.subscription(async ({ ctx, input }) => {
const boardSettings = await getServerSettingByKeyAsync(ctx.db, "board");
if (boardSettings.forceDisableStatus) {
throw new TRPCError({
code: "FORBIDDEN",
message: "Ping functionality is disabled by server settings",
});
}
const pingResult = await sendPingRequestAsync(input.url);
const repository = new AppRepository(ctx.db, ctx.session?.user ?? null);
const app = await repository.getByIdAsync(input.id);
if (!app) {
throw new TRPCError({
code: "NOT_FOUND",
message: "App not found",
});
}
const pingUrl = app.pingUrl ?? app.href;
if (!pingUrl) {
throw new TRPCError({
code: "CONFLICT",
message: "No URL to ping configured for this app",
});
}
await pingUrlChannel.addAsync(pingUrl);
return observable<{ url: string; statusCode: number; durationMs: number } | { url: string; error: string }>(
(emit) => {
emit.next({ url: input.url, ...pingResult });
const unsubscribe = pingChannel.subscribe((message) => {
// Only emit if same url
if (message.url !== input.url) return;
if (message.url !== pingUrl) return;
emit.next(message);
});
return () => {
unsubscribe();
void pingUrlChannel.removeAsync(input.url);
void pingUrlChannel.removeAsync(pingUrl);
};
},
);
@@ -9,7 +9,9 @@ import { createTRPCRouter, publicProcedure } from "../../trpc";
export const healthMonitoringRouter = createTRPCRouter({
getSystemHealthStatus: publicProcedure
.concat(createManyIntegrationMiddleware("query", "openmediavault", "dashDot", "truenas", "unraid", "mock"))
.concat(
createManyIntegrationMiddleware("query", "openmediavault", "dashDot", "truenas", "unraid", "glances", "mock"),
)
.query(async ({ ctx }) => {
return await Promise.all(
ctx.integrations.map(async (integration) => {
@@ -26,7 +28,9 @@ export const healthMonitoringRouter = createTRPCRouter({
);
}),
subscribeSystemHealthStatus: publicProcedure
.concat(createManyIntegrationMiddleware("query", "openmediavault", "dashDot", "truenas", "unraid", "mock"))
.concat(
createManyIntegrationMiddleware("query", "openmediavault", "dashDot", "truenas", "unraid", "glances", "mock"),
)
.subscription(({ ctx }) => {
return observable<{ integrationId: string; healthInfo: SystemHealthMonitoring; timestamp: Date }>((emit) => {
const unsubscribes: (() => void)[] = [];
+73 -3
View File
@@ -1,20 +1,30 @@
import SuperJSON from "superjson";
import { z } from "zod/v4";
import type { Session } from "@homarr/auth";
import type { Database } from "@homarr/db";
import { eq } from "@homarr/db";
import { items, users } from "@homarr/db/schema";
import { rssFeedsRequestHandler } from "@homarr/request-handler/rss-feeds";
import type { WidgetComponentProps } from "../../../../widgets/src";
import { createTRPCRouter, publicProcedure } from "../../trpc";
export const rssFeedRouter = createTRPCRouter({
getFeeds: publicProcedure
.input(
z.object({
urls: z.array(z.string()),
urls: z.array(z.string()).max(100),
maximumAmountPosts: z.number(),
}),
)
.query(async ({ input }) => {
.query(async ({ ctx, input }) => {
const urls = (await canAccessAllFeedsAsync(ctx.db, ctx.session))
? input.urls
: await restrictUrlsAsync(ctx.db, input.urls);
const rssFeeds = await Promise.all(
input.urls.map(async (url) => {
urls.map(async (url) => {
const innerHandler = rssFeedsRequestHandler.handler({
url,
count: input.maximumAmountPosts,
@@ -35,3 +45,63 @@ export const rssFeedRouter = createTRPCRouter({
});
}),
});
export async function canAccessAllFeedsAsync(db: Database, session: Session | null) {
// Unauthenticated users can never access all feeds
if (!session) return false;
// Users with those permissions can modify a board and therefore add a rss feed widget with any feed url
if (session.user.permissions.includes("board-create") || session.user.permissions.includes("board-modify-all")) {
return true;
}
const user = await db.query.users.findFirst({
where: eq(users.id, session.user.id),
with: {
boards: {
columns: { id: true },
},
boardPermissions: true,
groups: {
with: {
group: {
with: { boardPermissions: true },
},
},
},
},
});
// Should never happen as the user is authenticated, but just in case
if (!user) return false;
// If user is owner of any board he has full access and can therefore create widgets with any feed url
if (user.boards.length >= 1) return true;
// If user has direct permissions on any board that allow modifying it, he can add a rss feed widget with any feed url
if (user.boardPermissions.some(({ permission }) => permission === "modify" || permission === "full")) {
return true;
}
// If user is in a group that has permissions on any board that allow modifying it, he can add a rss feed widget with any feed url
if (
user.groups.some(({ group }) =>
group.boardPermissions.some(({ permission }) => permission === "modify" || permission === "full"),
)
) {
return true;
}
// Fallback to not allowing access to all feeds
return false;
}
export async function restrictUrlsAsync(db: Database, urls: string[]) {
const rssFeedItems = await db.query.items.findMany({
where: eq(items.kind, "rssFeed"),
});
const configuredUrls = rssFeedItems
.map((item) => SuperJSON.parse<WidgetComponentProps<"rssFeed">["options"]>(item.options))
.flatMap((options) => options.feedUrls);
return urls.filter((url) => configuredUrls.includes(url));
}
+6 -6
View File
@@ -33,11 +33,11 @@
"@homarr/validation": "workspace:^0.1.0",
"bcrypt": "^6.0.0",
"cookies": "^0.9.1",
"ldapts": "8.1.3",
"next": "16.1.3",
"ldapts": "8.1.6",
"next": "16.1.6",
"next-auth": "5.0.0-beta.30",
"react": "19.2.3",
"react-dom": "19.2.3",
"react": "19.2.4",
"react-dom": "19.2.4",
"zod": "^4.2.1"
},
"devDependencies": {
@@ -46,8 +46,8 @@
"@homarr/tsconfig": "workspace:^0.1.0",
"@types/bcrypt": "6.0.0",
"@types/cookies": "0.9.2",
"eslint": "^9.39.2",
"prettier": "^3.8.0",
"eslint": "^9.39.3",
"prettier": "^3.8.1",
"typescript": "^5.9.3"
}
}
+3 -3
View File
@@ -25,14 +25,14 @@
"prettier": "@homarr/prettier-config",
"dependencies": {
"@homarr/api": "workspace:^0.1.0",
"react": "19.2.3",
"react-dom": "19.2.3"
"react": "19.2.4",
"react-dom": "19.2.4"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+3 -3
View File
@@ -28,14 +28,14 @@
"@homarr/common": "workspace:^0.1.0",
"@homarr/db": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"dotenv": "^17.2.3"
"dotenv": "^17.3.1"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"esbuild": "^0.27.2",
"eslint": "^9.39.2",
"esbuild": "^0.27.3",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+6 -5
View File
@@ -27,12 +27,13 @@
"prettier": "@homarr/prettier-config",
"dependencies": {
"@homarr/core": "workspace:^0.1.0",
"@paralleldrive/cuid2": "^3.1.0",
"@paralleldrive/cuid2": "^3.3.0",
"cookie": "1.1.1",
"dayjs": "^1.11.19",
"next": "16.1.3",
"next": "16.1.6",
"octokit": "^5.0.5",
"react": "19.2.3",
"react-dom": "19.2.3",
"react": "19.2.4",
"react-dom": "19.2.4",
"undici": "7.18.2",
"zod": "^4.2.1",
"zod-validation-error": "^5.0.0"
@@ -41,7 +42,7 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+3 -3
View File
@@ -1,10 +1,10 @@
import type { SerializeOptions } from "cookie";
import { parse, serialize } from "cookie";
import { parseCookie, stringifySetCookie } from "cookie";
export function parseCookies(cookieString: string) {
return parse(cookieString);
return parseCookie(cookieString);
}
export function setClientCookie(name: string, value: string, options: SerializeOptions = {}) {
document.cookie = serialize(name, value, options);
document.cookie = stringifySetCookie(name, value, options);
}
+4 -4
View File
@@ -41,9 +41,9 @@
"better-sqlite3": "^12.6.2",
"dns-caching": "^0.2.9",
"drizzle-orm": "^0.45.1",
"ioredis": "5.9.2",
"mysql2": "3.16.1",
"pg": "^8.17.1",
"ioredis": "5.9.3",
"mysql2": "3.17.4",
"pg": "^8.18.0",
"superjson": "2.2.6",
"winston": "3.19.0",
"zod": "^4.2.1"
@@ -54,7 +54,7 @@
"@homarr/tsconfig": "workspace:^0.1.0",
"@types/better-sqlite3": "7.6.13",
"@types/pg": "^8.16.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+7 -7
View File
@@ -28,12 +28,12 @@
"@homarr/common": "workspace:^0.1.0",
"@homarr/core": "workspace:^0.1.0",
"@homarr/cron-jobs": "workspace:^0.1.0",
"@tanstack/react-query": "^5.90.19",
"@trpc/client": "^11.8.1",
"@trpc/server": "^11.8.1",
"@trpc/tanstack-react-query": "^11.8.1",
"@tanstack/react-query": "^5.90.21",
"@trpc/client": "^11.10.0",
"@trpc/server": "^11.10.0",
"@trpc/tanstack-react-query": "^11.10.0",
"node-cron": "^4.2.1",
"react": "19.2.3",
"react": "19.2.4",
"zod": "^4.2.1"
},
"devDependencies": {
@@ -41,8 +41,8 @@
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"@types/node-cron": "^3.0.11",
"@types/react": "19.2.8",
"eslint": "^9.39.2",
"@types/react": "19.2.14",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+9 -1
View File
@@ -17,7 +17,15 @@ export interface IJobManager {
updateIntervalAsync(name: JobGroupKeys, cron: string): Promise<void>;
disableAsync(name: JobGroupKeys): Promise<void>;
enableAsync(name: JobGroupKeys): Promise<void>;
getAllAsync(): Promise<{ name: JobGroupKeys; cron: string; preventManualExecution: boolean; isEnabled: boolean }[]>;
getAllAsync(): Promise<
{
name: JobGroupKeys;
cron: string;
preventManualExecution: boolean;
preventCustomInterval: boolean;
isEnabled: boolean;
}[]
>;
}
const t = initTRPC
+1 -1
View File
@@ -29,7 +29,7 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+1 -1
View File
@@ -34,7 +34,7 @@
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"@types/node-cron": "^3.0.11",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+10 -8
View File
@@ -19,6 +19,7 @@ export interface CreateCronJobCreatorOptions<TAllowedNames extends string> {
interface CreateCronJobOptions {
runOnStart?: boolean;
preventManualExecution?: boolean;
preventCustomInterval?: boolean;
expectedMaximumDurationInMillis?: number;
beforeStart?: () => MaybePromise<void>;
}
@@ -78,14 +79,14 @@ const createCallback = <TAllowedNames extends string, TName extends TAllowedName
where: (cronJobConfigurations, { eq }) => eq(cronJobConfigurations.name, name),
});
const scheduledTask = createTask(
configuration?.cronExpression ?? defaultCronExpression,
() => void catchingCallbackAsync(),
{
name,
timezone: creatorOptions.timezone,
},
);
const cronExpression = options.preventCustomInterval
? defaultCronExpression
: (configuration?.cronExpression ?? defaultCronExpression);
const scheduledTask = createTask(cronExpression, () => void catchingCallbackAsync(), {
name,
timezone: creatorOptions.timezone,
});
creatorOptions.logger.logDebug("The scheduled task for cron job was created", {
name,
cronExpression: defaultCronExpression,
@@ -114,6 +115,7 @@ const createCallback = <TAllowedNames extends string, TName extends TAllowedName
await catchingCallbackAsync();
},
preventManualExecution: options.preventManualExecution ?? false,
preventCustomInterval: options.preventCustomInterval ?? false,
};
};
};
+1 -1
View File
@@ -44,7 +44,7 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+1
View File
@@ -9,6 +9,7 @@ import { createCronJob } from "../lib";
export const analyticsJob = createCronJob("analytics", EVERY_WEEK, {
runOnStart: true,
preventManualExecution: true,
preventCustomInterval: true,
}).withCallback(async () => {
if (env.NO_EXTERNAL_CONNECTION) return;
const analyticSetting = await getServerSettingByKeyAsync(db, "analytics");
+11 -11
View File
@@ -47,17 +47,17 @@
"@homarr/core": "workspace:^0.1.0",
"@homarr/definitions": "workspace:^0.1.0",
"@homarr/server-settings": "workspace:^0.1.0",
"@mantine/core": "^8.3.12",
"@paralleldrive/cuid2": "^3.1.0",
"@testcontainers/mysql": "^11.11.0",
"@testcontainers/postgresql": "^11.11.0",
"@mantine/core": "^8.3.15",
"@paralleldrive/cuid2": "^3.3.0",
"@testcontainers/mysql": "^11.12.0",
"@testcontainers/postgresql": "^11.12.0",
"better-sqlite3": "^12.6.2",
"dotenv": "^17.2.3",
"drizzle-kit": "^0.31.8",
"dotenv": "^17.3.1",
"drizzle-kit": "^0.31.9",
"drizzle-orm": "^0.45.1",
"drizzle-zod": "^0.8.3",
"mysql2": "3.16.1",
"pg": "^8.17.1",
"mysql2": "3.17.4",
"pg": "^8.18.0",
"superjson": "2.2.6"
},
"devDependencies": {
@@ -67,9 +67,9 @@
"@types/better-sqlite3": "7.6.13",
"@types/pg": "^8.16.0",
"dotenv-cli": "^11.0.0",
"esbuild": "^0.27.2",
"eslint": "^9.39.2",
"prettier": "^3.8.0",
"esbuild": "^0.27.3",
"eslint": "^9.39.3",
"prettier": "^3.8.1",
"tsx": "4.20.4",
"typescript": "^5.9.3"
}
+2 -2
View File
@@ -24,14 +24,14 @@
"prettier": "@homarr/prettier-config",
"dependencies": {
"@homarr/common": "workspace:^0.1.0",
"fast-xml-parser": "^5.3.3",
"fast-xml-parser": "^5.3.7",
"zod": "^4.2.1"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"tsx": "4.20.4",
"typescript": "^5.9.3"
}
@@ -36,6 +36,7 @@ export type HomarrDocumentationPath =
| "/blog/tags/update"
| "/blog/tags/version"
| "/blog/translations"
| "/carbon-test"
| "/search"
| "/docs/tags"
| "/docs/tags/active-directory"
+15
View File
@@ -73,6 +73,14 @@ export const integrationDefs = {
category: ["downloadClient", "torrent", "miscellaneous"],
documentationUrl: createDocumentationLink("/docs/integrations/aria2"),
},
slskd: {
name: "Slskd",
secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/slskd.svg",
category: ["downloadClient", "miscellaneous"],
// @ts-expect-error - docs page will be created when integration is merged
documentationUrl: createDocumentationLink("/docs/integrations/slskd"),
},
sonarr: {
name: "Sonarr",
secretKinds: [["apiKey"]],
@@ -178,6 +186,13 @@ export const integrationDefs = {
category: ["healthMonitoring"],
documentationUrl: createDocumentationLink("/docs/integrations/dash-dot"),
},
glances: {
name: "Glances",
secretKinds: [[]],
iconUrl: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/glances.svg",
category: ["healthMonitoring"],
documentationUrl: null,
},
tdarr: {
name: "Tdarr",
secretKinds: [[], ["apiKey"]],
+2 -2
View File
@@ -32,8 +32,8 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"@types/dockerode": "^4.0.0",
"eslint": "^9.39.2",
"@types/dockerode": "^4.0.1",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+2 -2
View File
@@ -26,7 +26,7 @@
"@homarr/common": "workspace:^0.1.0",
"@homarr/translation": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"@mantine/form": "^8.3.12",
"@mantine/form": "^8.3.15",
"mantine-form-zod-resolver": "^1.3.0",
"zod": "^4.2.1"
},
@@ -34,7 +34,7 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+3 -3
View File
@@ -30,15 +30,15 @@
"@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"@mantine/core": "^8.3.12",
"react": "19.2.3",
"@mantine/core": "^8.3.15",
"react": "19.2.4",
"zod": "^4.2.1"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+1 -1
View File
@@ -31,7 +31,7 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+1 -1
View File
@@ -32,7 +32,7 @@
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"@types/bcrypt": "6.0.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+5 -5
View File
@@ -25,8 +25,8 @@
},
"prettier": "@homarr/prettier-config",
"dependencies": {
"@ctrl/deluge": "^7.5.0",
"@ctrl/qbittorrent": "^9.11.0",
"@ctrl/deluge": "^7.5.2",
"@ctrl/qbittorrent": "^9.11.2",
"@ctrl/transmission": "^7.4.0",
"@gitbeaker/rest": "^43.8.0",
"@homarr/common": "workspace:^0.1.0",
@@ -39,13 +39,13 @@
"@homarr/translation": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"@jellyfin/sdk": "^0.13.0",
"@octokit/auth-app": "^8.1.2",
"@octokit/auth-app": "^8.2.0",
"ical.js": "^2.2.1",
"maria2": "^0.4.1",
"node-ical": "^0.22.1",
"octokit": "^5.0.5",
"proxmox-api": "1.1.1",
"tsdav": "^2.1.6",
"tsdav": "^2.1.8",
"undici": "7.18.2",
"xml2js": "^0.6.2",
"zod": "^4.2.1"
@@ -56,7 +56,7 @@
"@homarr/tsconfig": "workspace:^0.1.0",
"@types/node-unifi": "^2.5.1",
"@types/xml2js": "^0.4.14",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
@@ -10,11 +10,13 @@ import { DelugeIntegration } from "../download-client/deluge/deluge-integration"
import { NzbGetIntegration } from "../download-client/nzbget/nzbget-integration";
import { QBitTorrentIntegration } from "../download-client/qbittorrent/qbittorrent-integration";
import { SabnzbdIntegration } from "../download-client/sabnzbd/sabnzbd-integration";
import { SlskdIntegration } from "../download-client/slskd/slskd-integration";
import { TransmissionIntegration } from "../download-client/transmission/transmission-integration";
import { EmbyIntegration } from "../emby/emby-integration";
import { GitHubContainerRegistryIntegration } from "../github-container-registry/github-container-registry-integration";
import { GithubIntegration } from "../github/github-integration";
import { GitlabIntegration } from "../gitlab/gitlab-integration";
import { GlancesIntegration } from "../glances/glances-integration";
import { HomeAssistantIntegration } from "../homeassistant/homeassistant-integration";
import { ICalIntegration } from "../ical/ical-integration";
import { JellyfinIntegration } from "../jellyfin/jellyfin-integration";
@@ -77,6 +79,7 @@ export const integrationCreators = {
qBittorrent: QBitTorrentIntegration,
deluge: DelugeIntegration,
transmission: TransmissionIntegration,
slskd: SlskdIntegration,
aria2: Aria2Integration,
jellyseerr: JellyseerrIntegration,
overseerr: OverseerrIntegration,
@@ -105,6 +108,7 @@ export const integrationCreators = {
truenas: TrueNasIntegration,
unraid: UnraidIntegration,
coolify: CoolifyIntegration,
glances: GlancesIntegration,
} satisfies Record<IntegrationKind, IntegrationInstance | [(input: IntegrationInput) => Promise<Integration>]>;
type IntegrationInstanceOfKind<TKind extends keyof typeof integrationCreators> = {
@@ -0,0 +1,244 @@
import dayjs from "dayjs";
import type { RequestInit } from "undici";
import { ResponseError } from "@homarr/common/server";
import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http";
import { createLogger } from "@homarr/core/infrastructure/logs";
import { ErrorWithMetadata } from "@homarr/core/infrastructure/logs/error";
import type { IntegrationTestingInput } from "../../base/integration";
import { Integration } from "../../base/integration";
import { TestConnectionError } from "../../base/test-connection/test-connection-error";
import type { TestingResult } from "../../base/test-connection/test-connection-service";
import type { DownloadClientJobsAndStatus } from "../../interfaces/downloads/download-client-data";
import type { IDownloadClientIntegration } from "../../interfaces/downloads/download-client-integration";
import type { DownloadClientItem } from "../../interfaces/downloads/download-client-items";
interface SlskdUserAndDownloads {
directories: {
files: {
id: string;
filename: string;
size: number;
percentComplete: number;
averageSpeed: number;
/**
* Time in hh:mm:ss format.
* Optional, undefined when aborted or errored.
*/
remainingTime?: string;
/**
* A bit-wise combination of the state enums.
*/
state: string;
/**
* ISO date when the file was requested at.
* "enqueued" and "started" are different things.
*/
requestedAt: string;
}[];
}[];
}
const logger = createLogger({ module: "slskd-integration" });
/**
* Implementation of the Slskd application for Soulseek https://github.com/slskd/slskd
* Slskd integration cannot pause or stop downloads, it can only list downloads.
*/
export class SlskdIntegration extends Integration implements IDownloadClientIntegration {
// eslint-disable-next-line no-restricted-syntax
public pauseQueueAsync(): Promise<void> {
return Promise.resolve();
}
// eslint-disable-next-line no-restricted-syntax
public pauseItemAsync(_: DownloadClientItem): Promise<void> {
return Promise.resolve();
}
// eslint-disable-next-line no-restricted-syntax
public resumeQueueAsync(): Promise<void> {
return Promise.resolve();
}
// eslint-disable-next-line no-restricted-syntax
public resumeItemAsync(_: DownloadClientItem): Promise<void> {
return Promise.resolve();
}
// eslint-disable-next-line no-restricted-syntax,id-length
public deleteItemAsync(_: DownloadClientItem, _2: boolean): Promise<void> {
return Promise.resolve();
}
protected async testingAsync(input: IntegrationTestingInput): Promise<TestingResult> {
const response = await input.fetchAsync(this.url("/api/v0/server"), {
headers: {
"X-API-Key": this.getSecretValue("apiKey"),
},
});
if (!response.ok) {
return TestConnectionError.StatusResult({
status: response.status,
url: response.url,
});
}
await response.json();
return {
success: true,
};
}
public async getClientJobsAndStatusAsync(input: { limit: number }): Promise<DownloadClientJobsAndStatus> {
const downloads = await this.getDownloadsAsync();
const flatFiles = downloads.flatMap((user) => user.directories).flatMap((directory) => directory.files);
return {
status: {
paused: false, // slskd cannot be paused
rates: {
down: flatFiles.reduce((acc, file) => acc + file.averageSpeed, 0),
up: 0, // slskd does not upload except sharing which isn't what we want to show in downloads
},
types: ["miscellaneous"],
},
items: flatFiles.slice(0, input.limit).map((file, index) => {
const remainingTimeParts = file.remainingTime ? file.remainingTime.split(":") : null;
// The file name returned from API includes the full remote path, which is not relevant for Homarr.
// We remove everything before the last slash to beautify the file name.
const actualFileName = file.filename.split("\\").at(-1);
return {
id: file.id,
name: actualFileName ?? file.filename,
size: file.size,
time: remainingTimeParts
? dayjs
.duration({
hours: Number(remainingTimeParts[0]),
minutes: Number(remainingTimeParts[1]),
seconds: Number(remainingTimeParts[2]),
})
.as("milliseconds")
: 0,
progress: file.percentComplete / 100,
type: "miscellaneous",
state: this.getDownloadState(file),
added: dayjs(file.requestedAt).unix() * 1000,
index,
};
}),
};
}
private async getDownloadsAsync(): Promise<SlskdUserAndDownloads[]> {
const response = await this.makeRequestAsync("/api/v0/transfers/downloads", { method: "GET" });
return response as SlskdUserAndDownloads[];
}
private async makeRequestAsync(
path: `/${string}`,
options: RequestInit & { timeout?: number } = {},
): Promise<unknown> {
const response = await fetchWithTrustedCertificatesAsync(this.url(path), {
...options,
headers: {
"X-API-Key": this.getSecretValue("apiKey"),
},
});
if (!response.ok) {
throw new ResponseError(response);
}
const contentType = response.headers.get("content-type");
if (contentType?.includes("application/json")) {
return response.json();
}
return response.text();
}
private getDownloadState(
item: SlskdUserAndDownloads["directories"][number]["files"][number],
): DownloadClientItem["state"] {
try {
const mappedStates = parseTransferStateArray(item.state);
if (mappedStates.includes(TransferState.InProgress)) {
return "downloading";
}
if (
mappedStates.includes(TransferState.Errored) ||
mappedStates.includes(TransferState.Aborted) ||
mappedStates.includes(TransferState.TimedOut) ||
mappedStates.includes(TransferState.Rejected) ||
mappedStates.includes(TransferState.Cancelled)
) {
return "failed";
}
if (mappedStates.includes(TransferState.Queued) || mappedStates.includes(TransferState.Initializing)) {
return "processing";
}
// "completed" must come last, since above enums are bit-wise combined even if they failed
if (mappedStates.includes(TransferState.Completed) || mappedStates.includes(TransferState.Succeeded)) {
return "completed";
}
logger.warn(
`Unable to map the SLSKD transfer state enum '${mappedStates.join(",")}'. Will fall back to 'unknown'`,
);
return "unknown";
} catch (error) {
logger.error(
new ErrorWithMetadata(
`Unable to map the SLSKD transfer states '${item.state}' due to an exception in the translation. Will fall back to 'unknown'. This is likely a bug.`,
undefined,
{
cause: error,
},
),
);
return "unknown";
}
}
}
/**
* Copy of the transfer states of SLSKD, copied from the following file:
* https://github.com/slskd/slskd/blob/86dc6072a28876abfdeb1f5dbb7dfc99ea8e1805/src/slskd/Core/Data/Migrations/Z04012025_TransferStateMigration.cs#L217-L234
*/
export enum TransferState {
None,
Requested,
Queued,
Initializing,
InProgress,
Completed,
Succeeded,
Cancelled,
TimedOut,
Errored,
Rejected,
Aborted,
}
export function parseTransferStateArray(csv: string, separator = ","): TransferState[] {
const parts = csv
.split(separator)
.map((part) => part.trim())
.filter(Boolean);
// @ts-expect-error use string to index
return parts.map((part) => TransferState[part] as TransferState);
}
@@ -0,0 +1,142 @@
import dayjs from "dayjs";
import { z } from "zod/v4";
import { ResponseError } from "@homarr/common/server";
import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/http";
import type { IntegrationInput, IntegrationTestingInput } from "../base/integration";
import { Integration } from "../base/integration";
import type { SessionStore } from "../base/session-store";
import { createSessionStore } from "../base/session-store";
import { TestConnectionError } from "../base/test-connection/test-connection-error";
import type { TestingResult } from "../base/test-connection/test-connection-service";
import type { ISystemHealthMonitoringIntegration } from "../interfaces/health-monitoring/health-monitoring-integration";
import type { SystemHealthMonitoring } from "../types";
export class GlancesIntegration extends Integration implements ISystemHealthMonitoringIntegration {
private readonly sessionStore: SessionStore<{ version: string }>;
constructor(integration: IntegrationInput) {
super(integration);
this.sessionStore = createSessionStore(integration);
}
public async getSystemInfoAsync(): Promise<SystemHealthMonitoring> {
let session = await this.sessionStore.getAsync();
if (session == null) {
await this.sessionStore.setAsync({
version: await this.getGlancesVersionAsync(),
});
// update the store to re-use the values below.
session = await this.sessionStore.getAsync();
}
if (session == null) throw new Error("Session was unexpectitly null");
const stats = await this.getAllStatsAsync();
return {
cpuUtilization: stats.cpu.total,
memUsedInBytes: stats.mem.used,
memAvailableInBytes: stats.mem.total - stats.mem.used,
network: {
down: stats.network.reduce((acc, net) => net.bytes_recv_rate_per_sec + acc, 0),
up: stats.network.reduce((acc, net) => net.bytes_sent_rate_per_sec + acc, 0),
},
availablePkgUpdates: 0,
version: session.version,
fileSystem: stats.fs.map((fileSystem) => ({
deviceName: fileSystem.device_name,
used: `${fileSystem.used}`,
available: `${fileSystem.free}`,
percentage: fileSystem.percent,
})),
uptime: stats.uptime.as("seconds"),
rebootRequired: false,
cpuModelName: stats.quicklook.cpu_name,
loadAverage: null,
smart: [],
cpuTemp: undefined,
};
}
private async getGlancesVersionAsync() {
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/4/version"));
if (!response.ok) {
throw new ResponseError(response);
}
return await response.text();
}
private async getAllStatsAsync() {
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/4/all"));
if (!response.ok) {
throw new ResponseError(response);
}
return allSchema.parseAsync(await response.json());
}
protected async testingAsync(_: IntegrationTestingInput): Promise<TestingResult> {
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/4/status"), {
headers: { "User-Agent": "Homarr" },
});
if (!response.ok) {
return TestConnectionError.StatusResult(response);
}
return { success: true };
}
}
const regex = /^(?:(?<days>\d+) days, )?(?<hours>\d+):(?<minutes>\d+):(?<seconds>\d+)$/m;
const allSchema = z.object({
cpu: z.object({
total: z.number().min(0).max(100),
}),
mem: z.object({
total: z.number().min(0),
used: z.number().min(0),
free: z.number().min(0),
}),
network: z.array(
z.object({
bytes_sent_rate_per_sec: z.number().min(0),
bytes_recv_rate_per_sec: z.number().min(0),
}),
),
fs: z.array(
z.object({
device_name: z.string(),
used: z.number().min(0),
free: z.number().min(0),
percent: z.number().min(0).max(100),
}),
),
uptime: z
.string()
.regex(new RegExp(regex))
.transform((uptime) => {
const match = regex.exec(uptime);
if (!match?.groups) {
throw new Error(`Unable to parse uptime value '${uptime}' with regex.`);
}
const days = "days" in match.groups ? Number(match.groups.days) : undefined;
const hours = "hours" in match.groups ? Number(match.groups.hours) : undefined;
const minutes = "minutes" in match.groups ? Number(match.groups.minutes) : undefined;
const seconds = "seconds" in match.groups ? Number(match.groups.seconds) : undefined;
return dayjs.duration({ days, hours, minutes, seconds });
}),
quicklook: z.object({
cpu_name: z.string(),
}),
});
+2
View File
@@ -5,6 +5,7 @@ export { DelugeIntegration } from "./download-client/deluge/deluge-integration";
export { NzbGetIntegration } from "./download-client/nzbget/nzbget-integration";
export { QBitTorrentIntegration } from "./download-client/qbittorrent/qbittorrent-integration";
export { SabnzbdIntegration } from "./download-client/sabnzbd/sabnzbd-integration";
export { SlskdIntegration } from "./download-client/slskd/slskd-integration";
export { TransmissionIntegration } from "./download-client/transmission/transmission-integration";
export { HomeAssistantIntegration } from "./homeassistant/homeassistant-integration";
export { JellyfinIntegration } from "./jellyfin/jellyfin-integration";
@@ -16,6 +17,7 @@ export { SonarrIntegration } from "./media-organizer/sonarr/sonarr-integration";
export { NextcloudIntegration } from "./nextcloud/nextcloud.integration";
export { NTFYIntegration } from "./ntfy/ntfy-integration";
export { OpenMediaVaultIntegration } from "./openmediavault/openmediavault-integration";
export { GlancesIntegration } from "./glances/glances-integration";
export { OverseerrIntegration } from "./overseerr/overseerr-integration";
export { PiHoleIntegrationV5 } from "./pi-hole/v5/pi-hole-integration-v5";
export { PiHoleIntegrationV6 } from "./pi-hole/v6/pi-hole-integration-v6";
@@ -115,9 +115,8 @@ export class OverseerrIntegration
}
public async getRequestsAsync(): Promise<MediaRequest[]> {
//Ensure to get all pending request first
const pendingRequests = await fetchWithTrustedCertificatesAsync(
this.url("/api/v1/request", { take: -1, filter: "pending" }),
this.url("/api/v1/request", { take: 20, filter: "pending" }),
{
headers: {
"X-Api-Key": this.getSecretValue("apiKey"),
@@ -125,7 +124,6 @@ export class OverseerrIntegration
},
);
//Change 20 to integration setting (set to -1 for all)
const allRequests = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/request", { take: 20 }), {
headers: {
"X-Api-Key": this.getSecretValue("apiKey"),
@@ -223,7 +221,7 @@ export class OverseerrIntegration
}
public async getUsersAsync(): Promise<RequestUser[]> {
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/user", { take: -1 }), {
const response = await fetchWithTrustedCertificatesAsync(this.url("/api/v1/user", { take: 10, sort: "requests" }), {
headers: {
"X-Api-Key": this.getSecretValue("apiKey"),
},
+6 -6
View File
@@ -33,19 +33,19 @@
"@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"@mantine/core": "^8.3.12",
"@tabler/icons-react": "^3.36.1",
"@mantine/core": "^8.3.15",
"@tabler/icons-react": "^3.37.1",
"dayjs": "^1.11.19",
"next": "16.1.3",
"react": "19.2.3",
"react-dom": "19.2.3",
"next": "16.1.6",
"react": "19.2.4",
"react-dom": "19.2.4",
"zod": "^4.2.1"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+4 -4
View File
@@ -24,15 +24,15 @@
"dependencies": {
"@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0",
"@mantine/core": "^8.3.12",
"@mantine/hooks": "^8.3.12",
"react": "19.2.3"
"@mantine/core": "^8.3.15",
"@mantine/hooks": "^8.3.15",
"react": "19.2.4"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+3 -3
View File
@@ -24,14 +24,14 @@
"prettier": "@homarr/prettier-config",
"dependencies": {
"@homarr/ui": "workspace:^0.1.0",
"@mantine/notifications": "^8.3.12",
"@tabler/icons-react": "^3.36.1"
"@mantine/notifications": "^8.3.15",
"@tabler/icons-react": "^3.37.1"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+6 -6
View File
@@ -37,12 +37,12 @@
"@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"@mantine/core": "^8.3.12",
"@mantine/hooks": "^8.3.12",
"@mantine/core": "^8.3.15",
"@mantine/hooks": "^8.3.15",
"adm-zip": "0.5.16",
"next": "16.1.3",
"react": "19.2.3",
"react-dom": "19.2.3",
"next": "16.1.6",
"react": "19.2.4",
"react-dom": "19.2.4",
"superjson": "2.2.6",
"zod": "^4.2.1",
"zod-form-data": "^3.0.1"
@@ -52,7 +52,7 @@
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"@types/adm-zip": "0.5.7",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+1 -1
View File
@@ -29,7 +29,7 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+1 -1
View File
@@ -29,7 +29,7 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+2 -2
View File
@@ -26,14 +26,14 @@
"@homarr/core": "workspace:^",
"@homarr/db": "workspace:^",
"@homarr/definitions": "workspace:^",
"ioredis": "5.9.2",
"ioredis": "5.9.3",
"superjson": "2.2.6"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+1 -1
View File
@@ -40,7 +40,7 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+1 -1
View File
@@ -108,7 +108,7 @@ const getFirstMediaProperty = (feedObject: object) => {
* We extend the feed with custom properties.
* This interface adds properties on top of the default ones.
*/
interface ExtendedFeedEntry extends FeedEntry {
export interface ExtendedFeedEntry extends FeedEntry {
enclosure?: string;
}
+1 -1
View File
@@ -29,7 +29,7 @@
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+5 -5
View File
@@ -25,16 +25,16 @@
"dependencies": {
"@homarr/db": "workspace:^0.1.0",
"@homarr/server-settings": "workspace:^0.1.0",
"@mantine/dates": "^8.3.12",
"next": "16.1.3",
"react": "19.2.3",
"react-dom": "19.2.3"
"@mantine/dates": "^8.3.15",
"next": "16.1.6",
"react": "19.2.4",
"react-dom": "19.2.4"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+9 -9
View File
@@ -33,21 +33,21 @@
"@homarr/settings": "workspace:^0.1.0",
"@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0",
"@mantine/core": "^8.3.12",
"@mantine/hooks": "^8.3.12",
"@mantine/spotlight": "^8.3.12",
"@tabler/icons-react": "^3.36.1",
"jotai": "^2.16.2",
"next": "16.1.3",
"react": "19.2.3",
"react-dom": "19.2.3",
"@mantine/core": "^8.3.15",
"@mantine/hooks": "^8.3.15",
"@mantine/spotlight": "^8.3.15",
"@tabler/icons-react": "^3.37.1",
"jotai": "^2.18.0",
"next": "16.1.6",
"react": "19.2.4",
"react-dom": "19.2.4",
"use-deep-compare-effect": "^1.8.1"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+5 -5
View File
@@ -32,16 +32,16 @@
"dayjs": "^1.11.19",
"deepmerge": "4.3.1",
"mantine-react-table": "2.0.0-beta.9",
"next": "16.1.3",
"next-intl": "4.7.0",
"react": "19.2.3",
"react-dom": "19.2.3"
"next": "16.1.6",
"next-intl": "4.8.3",
"react": "19.2.4",
"react-dom": "19.2.4"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.39.2",
"eslint": "^9.39.3",
"typescript": "^5.9.3"
}
}
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "",
"noResults": "",
"unsavedChanges": "",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "",
"hide": ""
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+66 -1
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "危险",
"noResults": "未找到结果",
"unsavedChanges": "你有未保存的更改 !",
"servers": "服务",
"applications": "应用",
"services": "服务",
"preview": {
"show": "显示预览",
"hide": "隐藏预览"
@@ -1960,6 +1963,39 @@
"internalServerError": "获取容器统计信息失败"
}
},
"coolify": {
"name": "Coolify",
"description": "您的 Coolify 实例及其服务器和应用一览",
"option": {
"showServers": {
"label": "显示服务"
},
"showApplications": {
"label": "显示应用程序"
},
"showServices": {
"label": "显示服务"
}
},
"empty": {
"servers": "未找到服务",
"applications": "未找到应用程序",
"services": "未找到服务"
},
"footer": {
"updated": "已更新 {when}"
},
"error": {
"noIntegration": "未配置 Coolify 集成",
"internalServerError": "获取 Coolify 数据失败"
},
"server": {
"buildServer": "编译"
},
"instances": {
"title": "实例"
}
},
"common": {
"location": {
"query": "城市/邮编",
@@ -2608,6 +2644,35 @@
"up": "上传",
"down": "下载"
}
},
"systemDisks": {
"name": "系统磁盘",
"description": "您系统的磁盘使用",
"option": {
"showTemperatureIfAvailable": {
"label": "如果可用则显示温度"
},
"displayMode": {
"label": "显示模式",
"option": {
"percentage": {
"label": "百分比 (例如76%)"
},
"absolute": {
"label": "绝对值 (例如,800GB / 1TB)"
},
"free": {
"label": "空闲空间百分比(例如24%空闲)"
}
}
},
"showBackgroundBar": {
"label": "显示背景使用栏"
}
},
"status": {
"unhealthy": "异常"
}
}
},
"widgetPreview": {
@@ -3240,7 +3305,7 @@
"title": "分析",
"general": {
"title": "发送匿名分析",
"text": "Homarr 将使用开源软件 Umami 发送匿名分析。它从不收集任何个人信息,因此完全符合 GDPR 和 CCPA 要求。我们鼓励您启用分析,因为它可以帮助我们的开源团队识别问题并确定待办事项的优先级。"
"text": "Homarr 将使用开源软件 Umami 发送匿名分析数据。启用后,我们会收集:Homarr 版本、数据库类型(MySQL/PostgreSQL/SQLite)、Docker/Kubernetes 状态、已启用的身份验证方法以及各项功能的数量。所有数据均为匿名且汇总收集——绝不收集任何个人信息、URL、名称或可识别数据。这有助于我们的开源团队了解使用模式并确定开发优先级。"
},
"widgetData": {
"title": "组件数据",
+66 -1
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "crwdns610:0crwdne610:0",
"noResults": "crwdns612:0crwdne612:0",
"unsavedChanges": "crwdns2784:0crwdne2784:0",
"servers": "crwdns3846:0crwdne3846:0",
"applications": "crwdns3848:0crwdne3848:0",
"services": "crwdns3850:0crwdne3850:0",
"preview": {
"show": "crwdns614:0crwdne614:0",
"hide": "crwdns616:0crwdne616:0"
@@ -1960,6 +1963,39 @@
"internalServerError": "crwdns3428:0crwdne3428:0"
}
},
"coolify": {
"name": "crwdns3852:0crwdne3852:0",
"description": "crwdns3854:0crwdne3854:0",
"option": {
"showServers": {
"label": "crwdns3856:0crwdne3856:0"
},
"showApplications": {
"label": "crwdns3858:0crwdne3858:0"
},
"showServices": {
"label": "crwdns3860:0crwdne3860:0"
}
},
"empty": {
"servers": "crwdns3862:0crwdne3862:0",
"applications": "crwdns3864:0crwdne3864:0",
"services": "crwdns3866:0crwdne3866:0"
},
"footer": {
"updated": "crwdns3868:0{when}crwdne3868:0"
},
"error": {
"noIntegration": "crwdns3870:0crwdne3870:0",
"internalServerError": "crwdns3872:0crwdne3872:0"
},
"server": {
"buildServer": "crwdns3874:0crwdne3874:0"
},
"instances": {
"title": "crwdns3876:0crwdne3876:0"
}
},
"common": {
"location": {
"query": "crwdns1110:0crwdne1110:0",
@@ -2608,6 +2644,35 @@
"up": "crwdns3610:0crwdne3610:0",
"down": "crwdns3612:0crwdne3612:0"
}
},
"systemDisks": {
"name": "crwdns3828:0crwdne3828:0",
"description": "crwdns3830:0crwdne3830:0",
"option": {
"showTemperatureIfAvailable": {
"label": "crwdns3832:0crwdne3832:0"
},
"displayMode": {
"label": "crwdns3834:0crwdne3834:0",
"option": {
"percentage": {
"label": "crwdns3836:0crwdne3836:0"
},
"absolute": {
"label": "crwdns3838:0crwdne3838:0"
},
"free": {
"label": "crwdns3840:0crwdne3840:0"
}
}
},
"showBackgroundBar": {
"label": "crwdns3842:0crwdne3842:0"
}
},
"status": {
"unhealthy": "crwdns3844:0crwdne3844:0"
}
}
},
"widgetPreview": {
@@ -3240,7 +3305,7 @@
"title": "crwdns1764:0crwdne1764:0",
"general": {
"title": "crwdns1766:0crwdne1766:0",
"text": "crwdns1768:0crwdne1768:0"
"text": "crwdns3878:0crwdne3878:0"
},
"widgetData": {
"title": "crwdns1770:0crwdne1770:0",
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Nebezpečná zóna",
"noResults": "Nebyly nalezeny žádné výsledky",
"unsavedChanges": "",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "Zobrazit náhled",
"hide": "Skrýt náhled"
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Farezone",
"noResults": "Ingen resultater fundet",
"unsavedChanges": "Du har ikke gemte ændringer!",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "Vis forhåndsvisning",
"hide": "Skjul forhåndsvisning"
@@ -1960,6 +1963,39 @@
"internalServerError": "Kunne ikke hente containerstatistik"
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "By / Postnummer",
@@ -2608,6 +2644,35 @@
"up": "OP",
"down": "NED"
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Gefahrenbereich",
"noResults": "Die Suche ergab keine Treffer",
"unsavedChanges": "Sie haben ungespeicherte Änderungen!",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "Vorschau ansehen",
"hide": "Vorschau ausblenden"
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "Stadt / Postleitzahl",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+69 -4
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Gefahrenbereich",
"noResults": "Die Suche ergab keine Treffer",
"unsavedChanges": "Sie haben ungespeicherte Änderungen!",
"servers": "Server",
"applications": "Apps",
"services": "Dienste",
"preview": {
"show": "Vorschau ansehen",
"hide": "Vorschau ausblenden"
@@ -1960,6 +1963,39 @@
"internalServerError": "Fehler beim Abrufen der Container Statistiken"
}
},
"coolify": {
"name": "Coolify",
"description": "Übersicht Ihrer Coolify-Instanz mit Servern und Anwendungen",
"option": {
"showServers": {
"label": "Server anzeigen"
},
"showApplications": {
"label": "Anwendungen anzeigen"
},
"showServices": {
"label": "Dienste anzeigen"
}
},
"empty": {
"servers": "Keine Server gefunden",
"applications": "Keine Anwendungen gefunden",
"services": "Keine Dienste gefunden"
},
"footer": {
"updated": "Aktualisiert {when}"
},
"error": {
"noIntegration": "Keine Coolify-Integration konfiguriert",
"internalServerError": "Fehler beim Abrufen der Coolify-Daten"
},
"server": {
"buildServer": "Version"
},
"instances": {
"title": "Instanzen"
}
},
"common": {
"location": {
"query": "Stadt / Postleitzahl",
@@ -2608,6 +2644,35 @@
"up": "OBEN",
"down": "UNTEN"
}
},
"systemDisks": {
"name": "Systemdatenträger",
"description": "Festplattennutzung Ihres Systems",
"option": {
"showTemperatureIfAvailable": {
"label": "Zeige Temperatur, falls verfügbar"
},
"displayMode": {
"label": "Anzeigemodus",
"option": {
"percentage": {
"label": "Prozentsatz (z.B. 76%)"
},
"absolute": {
"label": "Absolute Werte (z.B. 800GB / 1TB)"
},
"free": {
"label": "Prozentsatz freier Speicherplatz (z. B. 24% frei)"
}
}
},
"showBackgroundBar": {
"label": "Zeige Hintergrundnutzungsleiste"
}
},
"status": {
"unhealthy": "Fehlerhaft"
}
}
},
"widgetPreview": {
@@ -3240,7 +3305,7 @@
"title": "Nutzungsdaten",
"general": {
"title": "Anonymisierte Nutzungsdaten senden",
"text": "Homarr schickt anonymisierte Nutzungsdaten mit der Open-Source-Software Umami. Es sammelt zu keinem Zeitpunkt personenbezogene Daten und ist daher vollständig DPR & CCPA konform. Wir empfehlen diese Nutzungsdaten zu aktivieren, da es unserem Open-Source-Team hilft Probleme zu identifizieren und unserem Backlog ermöglicht Priorität einzuräumen."
"text": "Homarr sendet anonymisierte Analysen mit der Open-Source-Software Umami. Wenn aktiviert, sammeln wir die Homarr-Version, den Datenbanktyp (MySQL/PostgreSQL/SQLite), den Docker/Kubernetes Status, die Authentifizierungsmethoden und die Anzahl der einzelnen Features. Alle Daten sind anonym und aggregiert - es werden keine persönlichen Informationen, URLs, Namen oder identifizierbare Daten gesammelt. Dies hilft unserem Open-Source-Team, Nutzungsmuster zu verstehen und der Entwicklung Priorität einzuräumen."
},
"widgetData": {
"title": "Widget Daten",
@@ -3295,10 +3360,10 @@
}
},
"user": {
"title": "",
"title": "Benutzer",
"enableGravatar": {
"label": "",
"description": ""
"label": "Gravatar aktivieren",
"description": "Falls kein benutzerdefinierter Avatar gesetzt ist und eine E-Mail konfiguriert wurde, ist ein nutzen der Avatare von Libravatar/Gravatar möglich"
}
},
"search": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Επικίνδυνη Περιοχή",
"noResults": "Δεν βρέθηκαν αποτελέσματα",
"unsavedChanges": "",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "",
"hide": ""
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+226 -161
View File
@@ -836,19 +836,19 @@
"title": "Request error",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
"hostUnreachable": "The server could not be reached. This usually means the host is offline or unreachable from your network.",
"networkUnreachable": "The network is unreachable. Please check your Internet connection or network configuration.",
"refused": "The server refused the connection. It may not be running or is rejecting requests on the specified port.",
"reset": "The connection was unexpectedly closed by the server. This can happen if the server is unstable or restarted."
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
"notFound": "The server address could not be found. Please check the URL for typos or invalid domain names.",
"timeout": "DNS lookup timed out. This may be a temporary issue—please try again in a few moments.",
"noAnswer": "The DNS server didn't return a valid response. The domain may exist but has no valid records."
},
"timeout": {
"aborted": "",
"timeout": ""
"aborted": "The request was aborted before it could complete. This might be due to a user action or system timeout.",
"timeout": "The request took too long to complete and was timed out. Check your network or try again later."
}
}
}
@@ -920,8 +920,8 @@
"message": "The path is incorrect. Please double-check the URL"
},
"tooManyRequests": {
"title": "",
"message": ""
"title": "Too many requests in a given time",
"message": "There were too many requests. You are likely being rate-limited or rejected by the target system"
}
}
},
@@ -963,36 +963,36 @@
"newLabel": "New realm"
},
"personalAccessToken": {
"label": "",
"newLabel": ""
"label": "Personal Access Token",
"newLabel": "New Personal Access Token"
},
"topic": {
"label": "",
"newLabel": ""
"label": "Topic",
"newLabel": "New topic"
},
"url": {
"label": "",
"newLabel": ""
"label": "URL",
"newLabel": "New URL"
},
"opnsenseApiKey": {
"label": "",
"newLabel": ""
"label": "API Key (Key)",
"newLabel": "New API Key (Key)"
},
"opnsenseApiSecret": {
"label": "",
"newLabel": ""
"label": "API Key (Secret)",
"newLabel": "New API Key (Secret)"
},
"githubAppId": {
"label": "",
"newLabel": ""
"label": "App Id",
"newLabel": "New App Id"
},
"githubInstallationId": {
"label": "",
"newLabel": ""
"label": "Installation Id",
"newLabel": "New Installation Id"
},
"privateKey": {
"label": "",
"newLabel": ""
"label": "Private key",
"newLabel": "New private key"
}
}
},
@@ -1044,14 +1044,14 @@
}
},
"common": {
"success": "",
"success": "Success",
"beta": "Beta",
"error": "Alpha",
"action": {
"add": "Add",
"apply": "Apply",
"backToOverview": "Back to overview",
"change": "",
"change": "Change",
"create": "Create",
"createAnother": "Create and start over",
"edit": "Edit",
@@ -1063,7 +1063,7 @@
"cancel": "Cancel",
"delete": "Delete",
"discard": "Discard",
"close": "",
"close": "Close",
"confirm": "Confirm",
"continue": "Continue",
"previous": "Previous",
@@ -1138,6 +1138,9 @@
"dangerZone": "Danger zone",
"noResults": "No results have been found",
"unsavedChanges": "You have unsaved changes!",
"servers": "Servers",
"applications": "Apps",
"services": "Services",
"preview": {
"show": "Show a preview",
"hide": "Hide the preview"
@@ -1174,8 +1177,8 @@
},
"unit": {
"speed": {
"kilometersPerHour": "",
"milesPerHour": ""
"kilometersPerHour": "km/h",
"milesPerHour": "mph"
}
}
},
@@ -1190,7 +1193,7 @@
"label": "Title"
},
"customCssClasses": {
"label": ""
"label": "Custom CSS classes"
},
"borderColor": {
"label": "Border colour"
@@ -1223,75 +1226,75 @@
},
"remove": {
"title": "Remove category",
"message": ""
"message": "Are you sure you want to remove the category {name}?"
},
"edit": {
"title": "",
"submit": ""
"title": "Rename category",
"submit": "Rename category"
},
"menu": {
"label": {
"create": "",
"changePosition": ""
"create": "New category",
"changePosition": "Change position"
}
},
"openAllInNewTabs": {
"title": "",
"text": ""
"title": "Open all in tabs",
"text": "Some browsers may block the bulk-opening of tabs for security reasons. Homarr was unable to open all windows, because your browser blocked this action. Please allow \"Open pop-up windows\" and re-try."
}
}
},
"item": {
"action": {
"create": "",
"import": "",
"edit": "",
"moveResize": "",
"duplicate": "",
"remove": ""
"create": "New item",
"import": "Import item",
"edit": "Edit item",
"moveResize": "Move / resize item",
"duplicate": "Duplicate item",
"remove": "Remove item"
},
"menu": {
"label": {
"settings": ""
"settings": "Settings"
}
},
"create": {
"title": "",
"search": "",
"addToBoard": ""
"title": "Choose item to add",
"search": "Filter items",
"addToBoard": "Add to board"
},
"moveResize": {
"title": "",
"title": "Move / resize item",
"field": {
"width": {
"label": ""
"label": "Width"
},
"height": {
"label": ""
"label": "Height"
},
"xOffset": {
"label": ""
"label": "X offset"
},
"yOffset": {
"label": ""
"label": "Y offset"
}
}
},
"edit": {
"title": "",
"title": "Edit item",
"advancedOptions": {
"label": "",
"title": ""
"label": "Advanced options",
"title": "Advanced item options"
},
"field": {
"integrations": {
"label": ""
"label": "Integrations"
},
"title": {
"label": ""
"label": "Title"
},
"customCssClasses": {
"label": ""
"label": "Custom CSS classes"
},
"borderColor": {
"label": "Border colour"
@@ -1299,68 +1302,68 @@
}
},
"remove": {
"title": "",
"message": ""
"title": "Remove item",
"message": "Are you sure you want to remove this item?"
}
},
"widget": {
"app": {
"name": "",
"description": "",
"name": "App",
"description": "Embeds an app into the board.",
"option": {
"appId": {
"label": ""
"label": "Choose app"
},
"openInNewTab": {
"label": ""
"label": "Open in new tab"
},
"showTitle": {
"label": ""
"label": "Show app name"
},
"pingEnabled": {
"label": ""
"label": "Enable status check"
},
"layout": {
"label": "",
"label": "Layout",
"option": {
"row": "",
"row-reverse": "",
"column": "",
"column-reverse": ""
"row": "Horizontal",
"row-reverse": "Horizontal (reversed)",
"column": "Vertical",
"column-reverse": "Vertical (reversed)"
}
},
"descriptionDisplayMode": {
"label": "",
"description": "",
"label": "Description display mode",
"description": "Choose how to display the app description",
"option": {
"normal": "",
"tooltip": "",
"hidden": ""
"normal": "Within widget",
"tooltip": "As tooltip",
"hidden": "Hidden"
}
}
},
"error": {
"notFound": {
"label": "",
"tooltip": ""
"label": "No app",
"tooltip": "You have no valid app selected"
}
}
},
"bookmarks": {
"name": "",
"description": "",
"name": "Bookmarks",
"description": "Displays multiple app links",
"option": {
"title": {
"label": ""
"label": "Title"
},
"layout": {
"label": "",
"label": "Layout",
"option": {
"row": {
"label": ""
"label": "Horizontal"
},
"column": {
"label": ""
"label": "Vertical"
},
"grid": {
"label": ""
@@ -1424,46 +1427,46 @@
},
"dnsHoleControls": {
"name": "",
"description": "",
"description": "Control PiHole or AdGuard from your dashboard",
"option": {
"layout": {
"label": "",
"label": "Layout",
"option": {
"row": {
"label": ""
"label": "Horizontal"
},
"column": {
"label": ""
"label": "Vertical"
},
"grid": {
"label": ""
"label": "Grid"
}
}
},
"showToggleAllButtons": {
"label": ""
"label": "Show Toggle All Buttons"
}
},
"error": {
"internalServerError": ""
"internalServerError": "Failed to control DNS Hole"
},
"controls": {
"enableAll": "",
"disableAll": "",
"setTimer": "",
"set": "",
"enabled": "",
"disabled": "",
"processing": "",
"disconnected": "",
"hours": "",
"minutes": "",
"unlimited": ""
"enableAll": "Enable All",
"disableAll": "Disable All",
"setTimer": "Set Timer",
"set": "Set",
"enabled": "Enabled",
"disabled": "Disabled",
"processing": "Processing",
"disconnected": "Disconnected",
"hours": "Hours",
"minutes": "Minutes",
"unlimited": "Leave blank to unlimited"
}
},
"clock": {
"name": "",
"description": "",
"name": "Date and time",
"description": "Displays the current date and time.",
"option": {
"customTitleToggle": {
"label": "",
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
@@ -4251,52 +4316,52 @@
}
},
"page": {
"help": "",
"help": "Search for pages",
"group": {
"page": {
"title": "",
"title": "Pages",
"option": {
"manageHome": {
"label": ""
"label": "Manage home page"
},
"manageBoard": {
"label": ""
"label": "Manage boards"
},
"manageApp": {
"label": ""
"label": "Manage apps"
},
"manageIntegration": {
"label": ""
"label": "Manage integrations"
},
"manageSearchEngine": {
"label": ""
"label": "Manage search engines"
},
"manageMedia": {
"label": ""
"label": "Manage medias"
},
"manageUser": {
"label": ""
"label": "Manage users"
},
"manageInvite": {
"label": ""
"label": "Manage invites"
},
"manageGroup": {
"label": ""
"label": "Manage groups"
},
"manageDocker": {
"label": ""
"label": "Manage docker"
},
"manageApi": {
"label": ""
"label": "Swagger API"
},
"manageLog": {
"label": ""
"label": "View logs"
},
"manageTask": {
"label": ""
"label": "Manage tasks"
},
"manageSettings": {
"label": ""
"label": "Global settings"
},
"about": {
"label": ""
@@ -4378,44 +4443,44 @@
"title": "",
"notification": {
"success": {
"title": "",
"message": ""
"title": "Search engine created",
"message": "The search engine was created successfully"
},
"error": {
"title": "",
"message": ""
"title": "Search engine not created",
"message": "The search engine could not be created"
}
}
},
"edit": {
"title": "",
"title": "Edit search engine",
"notification": {
"success": {
"title": "",
"message": ""
"title": "Changes applied successfully",
"message": "The search engine was saved successfully"
},
"error": {
"title": "",
"message": ""
"title": "Unable to apply changes",
"message": "The search engine could not be saved"
}
},
"configControl": "",
"configControl": "Configuration",
"searchEngineType": {
"generic": "",
"fromIntegration": ""
"generic": "Generic",
"fromIntegration": "From integration"
}
},
"delete": {
"title": "",
"message": "",
"title": "Delete search engine",
"message": "Are you sure you want to delete the search engine {name}?",
"notification": {
"success": {
"title": "",
"message": ""
"title": "Search engine deleted",
"message": "The search engine was deleted successfully"
},
"error": {
"title": "",
"message": ""
"title": "Search engine not deleted",
"message": "The search engine could not be deleted"
}
}
}
@@ -4423,15 +4488,15 @@
"media": {
"request": {
"modal": {
"title": "",
"title": "Request \"{name}\"",
"table": {
"header": {
"season": "",
"episodes": ""
"season": "Season",
"episodes": "Episodes"
}
},
"button": {
"send": ""
"send": "Send request"
}
}
}
@@ -4441,44 +4506,44 @@
"certificate": {
"field": {
"hostname": {
"label": ""
"label": "Hostname"
},
"subject": {
"label": ""
"label": "Subject"
},
"issuer": {
"label": ""
"label": "Issuer"
},
"validFrom": {
"label": ""
"label": "Valid from"
},
"validTo": {
"label": ""
"label": "Valid to"
},
"serialNumber": {
"label": ""
"label": "Serial number"
},
"fingerprint": {
"label": ""
"label": "Fingerprint"
}
},
"page": {
"list": {
"title": "",
"description": "",
"title": "Trusted certificates",
"description": "Used by Homarr to request data from integrations.",
"noResults": {
"title": ""
"title": "There are no certificates yet"
},
"invalid": {
"title": "",
"description": ""
"title": "Invalid certificate",
"description": "Failed to parse certificate"
},
"expires": "",
"toHostnames": ""
"expires": "Expires {when}",
"toHostnames": "Trusted hostnames"
},
"hostnames": {
"title": "",
"description": "",
"title": "Trusted certificate hostnames",
"description": "Some certificates do not allow the specific domain Homarr uses to request them, because of this all trusted hostnames with their certificate thumbprints are used to bypass these restrictions.",
"noResults": {
"title": "There are no hostnames yet"
},
+1 -1
View File
@@ -3305,7 +3305,7 @@
"title": "Analytics",
"general": {
"title": "Send anonymous analytics",
"text": "Homarr will send anonymized analytics using the open source software Umami. It never collects any personal information and is therefore fully GDPR & CCPA compliant. We encourage you to enable analytics because it helps our open source team to identify issues and prioritize our backlog."
"text": "Homarr will send anonymized analytics using the open source software Umami. When enabled, we collect: Homarr version, database type (MySQL/PostgreSQL/SQLite), Docker/Kubernetes status, authentication methods enabled, and the number of each feature. All data is anonymous and aggregated - no personal information, URLs, names, or identifiable data is ever collected. This helps our open source team understand usage patterns and prioritize development."
},
"widgetData": {
"title": "Widget data",
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Zona de riesgo",
"noResults": "No se han encontrado resultados",
"unsavedChanges": "¡Tienes cambios sin guardar!",
"servers": "Servidores",
"applications": "Aplicaciones",
"services": "Servicios",
"preview": {
"show": "Mostrar vista previa",
"hide": "Ocultar vista previa"
@@ -1960,6 +1963,39 @@
"internalServerError": "No se pudo obtener las estadísticas de los contenedores"
}
},
"coolify": {
"name": "Coolify",
"description": "Resumen de su instancia de Coolify con servidores y aplicaciones",
"option": {
"showServers": {
"label": "Mostrar servidores"
},
"showApplications": {
"label": "Mostrar aplicaciones"
},
"showServices": {
"label": "Mostrar servicios"
}
},
"empty": {
"servers": "No se encontraron servidores",
"applications": "No se encontraron aplicaciones",
"services": "No se encontraron servicios"
},
"footer": {
"updated": "Actualizado {when}"
},
"error": {
"noIntegration": "No hay integración de Coolify configurada",
"internalServerError": "No se pudieron obtener los datos de Coolify"
},
"server": {
"buildServer": "Construir"
},
"instances": {
"title": "Instancias"
}
},
"common": {
"location": {
"query": "Ciudad / Código postal",
@@ -2608,6 +2644,35 @@
"up": "ENCENDIDO",
"down": "APAGADO"
}
},
"systemDisks": {
"name": "Discos del sistema",
"description": "Uso del disco de su sistema",
"option": {
"showTemperatureIfAvailable": {
"label": "Mostrar la temperatura si está disponible"
},
"displayMode": {
"label": "Modo de visualización",
"option": {
"percentage": {
"label": "Porcentaje (e.g., 76 %)"
},
"absolute": {
"label": "Valores absolutos (e.g., 800 GB / 1 TB)"
},
"free": {
"label": "Porcentaje de espacio libre (e.g., 24 % libre)"
}
}
},
"showBackgroundBar": {
"label": "Mostrar la barra de uso en segundo plano"
}
},
"status": {
"unhealthy": "Poco sano"
}
}
},
"widgetPreview": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "",
"noResults": "",
"unsavedChanges": "",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "",
"hide": ""
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Zone de danger",
"noResults": "Aucun résultat trouvé",
"unsavedChanges": "Vous avez des modifications non enregistrées !",
"servers": "Serveurs",
"applications": "Applications",
"services": "Services",
"preview": {
"show": "Afficher l’aperçu",
"hide": "Masquer l'aperçu"
@@ -1960,6 +1963,39 @@
"internalServerError": "Impossible de récupérer les statistiques des conteneurs"
}
},
"coolify": {
"name": "Coolify",
"description": "Aperçu de votre instance Coolify avec les serveurs et les applications",
"option": {
"showServers": {
"label": "Afficher les serveurs"
},
"showApplications": {
"label": "Afficher les applications"
},
"showServices": {
"label": "Afficher les services"
}
},
"empty": {
"servers": "Aucun serveur trouvé",
"applications": "Aucune application trouvée",
"services": "Aucun service trouvé"
},
"footer": {
"updated": "Mis à jour {when}"
},
"error": {
"noIntegration": "Aucune intégration de Coolify configurée",
"internalServerError": "Impossible de récupérer les données de Coolify"
},
"server": {
"buildServer": "Version"
},
"instances": {
"title": "Instances"
}
},
"common": {
"location": {
"query": "Ville / Code Postal",
@@ -2608,6 +2644,35 @@
"up": "UP",
"down": "HORS SERVICE"
}
},
"systemDisks": {
"name": "Disques système",
"description": "Utilisation du disque de votre système",
"option": {
"showTemperatureIfAvailable": {
"label": "Afficher la température si disponible"
},
"displayMode": {
"label": "Mode d'affichage",
"option": {
"percentage": {
"label": "Pourcentage (ex : 70%)"
},
"absolute": {
"label": "Valeurs absolues (ex. : 800 Go / 1 To)"
},
"free": {
"label": "Pourcentage d'espace libre (ex. : 24 % libre)"
}
}
},
"showBackgroundBar": {
"label": "Afficher la barre d'utilisation en arrière-plan"
}
},
"status": {
"unhealthy": "Dysfonctionnement"
}
}
},
"widgetPreview": {
+66 -1
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "אזור מסוכן",
"noResults": "לא נמצאו תוצאות",
"unsavedChanges": "ישנם שינויים שלא נשמרו!",
"servers": "שרתים",
"applications": "",
"services": "",
"preview": {
"show": "הצג תצוגה מקדימה",
"hide": "הסתר תצוגה המקדימה"
@@ -1960,6 +1963,39 @@
"internalServerError": "נכשל באחזור סטטיסטיקות המכולות"
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "עיר / מיקוד",
@@ -2608,6 +2644,35 @@
"up": "העלאה",
"down": "הורדה"
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
@@ -3295,7 +3360,7 @@
}
},
"user": {
"title": "",
"title": "משתמשים",
"enableGravatar": {
"label": "",
"description": ""
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Opasna zona",
"noResults": "Nije pronađen nijedan rezultat",
"unsavedChanges": "",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "",
"hide": ""
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Veszélyzóna",
"noResults": "Nincs eredmény",
"unsavedChanges": "",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "",
"hide": ""
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Zona pericolosa",
"noResults": "Nessun risultato trovato",
"unsavedChanges": "Ci sono modifiche non salvate!",
"servers": "Server",
"applications": "App",
"services": "Servizi",
"preview": {
"show": "Mostra anteprima",
"hide": "Nascondi anteprima"
@@ -1960,6 +1963,39 @@
"internalServerError": "Recupero statistiche container non riuscito"
}
},
"coolify": {
"name": "Coolify",
"description": "Panoramica della tua istanza Coolify con server e applicazioni",
"option": {
"showServers": {
"label": "Mostra server"
},
"showApplications": {
"label": "Mostra applicazioni"
},
"showServices": {
"label": "Mostra servizi"
}
},
"empty": {
"servers": "Nessun server trovato",
"applications": "Nessuna applicazione trovata",
"services": "Nessun servizio trovato"
},
"footer": {
"updated": "Aggiornato {when}"
},
"error": {
"noIntegration": "Nessuna integrazione di Coolify configurata",
"internalServerError": "Impossibile recuperare i dati Coolify"
},
"server": {
"buildServer": "Build"
},
"instances": {
"title": "Istanze"
}
},
"common": {
"location": {
"query": "Città / Codice postale",
@@ -2608,6 +2644,35 @@
"up": "SU",
"down": "DOWN"
}
},
"systemDisks": {
"name": "Dischi di sistema",
"description": "Uso del disco del sistema",
"option": {
"showTemperatureIfAvailable": {
"label": "Mostra temperatura se disponibile"
},
"displayMode": {
"label": "Modalità di visualizzazione",
"option": {
"percentage": {
"label": "Percentuale (es. 76%)"
},
"absolute": {
"label": "Valori assoluti (ad es. 800GB / 1TB)"
},
"free": {
"label": "Percentuale di spazio libero (ad es. 24% libero)"
}
}
},
"showBackgroundBar": {
"label": "Mostra barra di utilizzo in background"
}
},
"status": {
"unhealthy": "Compromesso"
}
}
},
"widgetPreview": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "危険な操作",
"noResults": "結果が見つかりません",
"unsavedChanges": "保存していない変更があります!",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "プレビューを表示",
"hide": "プレビューを閉じる"
@@ -1960,6 +1963,39 @@
"internalServerError": "コンテナステータスの取得に失敗しました"
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "都市/郵便番号",
@@ -2608,6 +2644,35 @@
"up": "UP",
"down": "DOWN"
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "위험한 설정",
"noResults": "결과를 찾을 수 없습니다.",
"unsavedChanges": "",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "",
"hide": ""
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "",
"noResults": "Rezultatų nerasta",
"unsavedChanges": "",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "",
"hide": ""
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Bīstamā zona",
"noResults": "Nav atrasts neviens rezultāts",
"unsavedChanges": "",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "",
"hide": ""
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Gevarenzone",
"noResults": "Geen resultaten gevonden",
"unsavedChanges": "Er zijn niet-opgeslagen wijzigingen!",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "Voorbeeld weergeven",
"hide": "Voorbeeld verbergen"
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "Stad / postcode",
@@ -2608,6 +2644,35 @@
"up": "OMHOOG",
"down": "OMLAAG"
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
+66 -1
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Faresonen",
"noResults": "Ingen resultater funnet",
"unsavedChanges": "Du har ulagrede endringer!",
"servers": "Servere",
"applications": "Apper",
"services": "Tjenester",
"preview": {
"show": "Vis forhåndsvisning",
"hide": "Skjul forhåndsvisning"
@@ -1960,6 +1963,39 @@
"internalServerError": "Kunne ikke hente containerstatistikk"
}
},
"coolify": {
"name": "Coolify",
"description": "Oversikt over din Coolify-instans med servere og apper",
"option": {
"showServers": {
"label": "Vis servere"
},
"showApplications": {
"label": "Vis applikasjoner"
},
"showServices": {
"label": "Vis tjenester"
}
},
"empty": {
"servers": "Ingen server funnet",
"applications": "Ingen applikasjoner funnet",
"services": "Ingen tjenester funnet"
},
"footer": {
"updated": "Oppdatert {when}"
},
"error": {
"noIntegration": "Ingen Coolify integrasjon konfigurert",
"internalServerError": "Kunne ikke hente Coolify data"
},
"server": {
"buildServer": "Bygg"
},
"instances": {
"title": "Instanser"
}
},
"common": {
"location": {
"query": "By / Postnummer",
@@ -2608,6 +2644,35 @@
"up": "OPP",
"down": "NED"
}
},
"systemDisks": {
"name": "Systemdisker",
"description": "Disk bruk av systemet",
"option": {
"showTemperatureIfAvailable": {
"label": "Vis temperatur hvis tilgjengelig"
},
"displayMode": {
"label": "Visningsmodus",
"option": {
"percentage": {
"label": "Prosentandel (f.eks. 76%)"
},
"absolute": {
"label": "Absolutte verdier (f.eks. 800GB / 1TB)"
},
"free": {
"label": "Prosentandel ledig plass (f.eks. 24% ledig)"
}
}
},
"showBackgroundBar": {
"label": "Vis bakgrunnsbrukslinje"
}
},
"status": {
"unhealthy": "Usunn"
}
}
},
"widgetPreview": {
@@ -3240,7 +3305,7 @@
"title": "Statistikk",
"general": {
"title": "Send anonym brukerdata",
"text": "Homarr vil sende anonymt brukerdata med åpen kildekode programvaren Umami. Det vil aldri samle inn personlig informasjon og følger derfor GDPR & CCPA fullstendig. Vi oppfordrer deg til å aktivere sending av brukerdata da det hjelper teamet vårt å identifisere problemer og sette prioritering."
"text": "Homarr vil sende anonymiserte analyser ved bruk av den åpne programvaren Umami. Når dette er aktivert, samler vi inn: Homarr-versjon, databastype (MySQL/PostgreSQL/SQLite), Docker/Kubernetes-status, aktiverte autentiseringsmetoder, og antallet av hver funksjon. Alle data er anonyme og aggregerte – ingen personlig informasjon, URL-er, navn eller identifiserbare data samles inn. Dette hjelper vårt open source-team med å forstå bruks‑mønstre og prioritere utvikling."
},
"widgetData": {
"title": "Widget data",
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Strefa zagrożenia",
"noResults": "Nie znaleziono żadnych wyników",
"unsavedChanges": "Masz niezapisane zmiany!",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "Pokaż podgląd",
"hide": "Ukryj podgląd"
@@ -1960,6 +1963,39 @@
"internalServerError": "Nie udało się pobrać statystyk kontenerów"
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "Miasto / kod pocztowy",
@@ -2608,6 +2644,35 @@
"up": "Aktywny",
"down": "Nieaktywny"
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
File diff suppressed because it is too large. Load diff
+65
View File
@@ -1138,6 +1138,9 @@
"dangerZone": "Zonă periculoasă",
"noResults": "Nici un rezultat găsit",
"unsavedChanges": "",
"servers": "",
"applications": "",
"services": "",
"preview": {
"show": "",
"hide": ""
@@ -1960,6 +1963,39 @@
"internalServerError": ""
}
},
"coolify": {
"name": "",
"description": "",
"option": {
"showServers": {
"label": ""
},
"showApplications": {
"label": ""
},
"showServices": {
"label": ""
}
},
"empty": {
"servers": "",
"applications": "",
"services": ""
},
"footer": {
"updated": ""
},
"error": {
"noIntegration": "",
"internalServerError": ""
},
"server": {
"buildServer": ""
},
"instances": {
"title": ""
}
},
"common": {
"location": {
"query": "",
@@ -2608,6 +2644,35 @@
"up": "",
"down": ""
}
},
"systemDisks": {
"name": "",
"description": "",
"option": {
"showTemperatureIfAvailable": {
"label": ""
},
"displayMode": {
"label": "",
"option": {
"percentage": {
"label": ""
},
"absolute": {
"label": ""
},
"free": {
"label": ""
}
}
},
"showBackgroundBar": {
"label": ""
}
},
"status": {
"unhealthy": ""
}
}
},
"widgetPreview": {
File diff suppressed because it is too large. Load diff
Loaded 100 of 120 files, more files were not shown because too many files have changed in this diff. Show more