Compare commits

...
Author SHA1 Message Date
Meier Lukas 0b94219002 perf: try to improve nextjs dev performance 2025-05-27 22:46:53 +02:00
homarr-crowdin[bot] 1575716f41 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2025-05-27 17:02:51 +00:00
homarr-renovate[bot] 8966e2ad8a fix(deps): update dependency @t3-oss/env-nextjs to ^0.13.6 (#3244)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-27 12:36:02 +00:00
homarr-renovate[bot] 816544a996 fix(deps): update mantine monorepo to ^8.0.2 (#3245)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-27 11:19:17 +00:00
homarr-renovate[bot] 9c323850bc fix(deps): update dependency jotai to ^2.12.5 (#3243)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-27 09:21:29 +00:00
homarr-renovate[bot] c3936237c0 chore(deps): update dependency @types/react to v19.1.6 (#3242)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-27 08:26:07 +00:00
homarr-renovate[bot] 9b8d1cbb66 chore(deps): update dependency esbuild to ^0.25.5 (#3241)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-27 04:27:15 +00:00
homarr-renovate[bot] 3062948939 fix(deps): update dependency zod to ^3.25.30 (#3239)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-27 03:13:49 +00:00
homarr-renovate[bot] 78f98edc41 fix(deps): update trpc monorepo to ^11.1.3 (#3240)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-27 01:14:03 +00:00
homarr-renovate[bot] 81ca6ef7b2 fix(deps): update dependency zod to ^3.25.29 (#3237)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-26 23:20:16 +00:00
homarr-renovate[bot] 71186908b9 fix(deps): update tanstack-query monorepo to ^5.77.2 (#3232)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-26 12:34:40 +00:00
Meier Lukas cbbf0c8dcf fix: navigating back results in navigation back to first page opened (#3224) 2025-05-26 11:41:09 +02:00
Meier Lukas 1d27da2230 fix(calendar): remove scrollbar for 2x2 (#3227) 2025-05-26 11:40:42 +02:00
homarr-crowdin[bot] d4ef212042 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2025-05-26 00:53:16 +00:00
homarr-renovate[bot] 5ea7a20677 fix(deps): update tanstack-query monorepo to ^5.77.1 (#3229)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-25 22:19:07 +00:00
Meier Lukas 05e159f566 fix: csp prevents fonts to load (#3225) 2025-05-25 16:39:20 +02:00
homarr-renovate[bot] 6d9e42cf5d chore(deps): update dependency @semantic-release/github to ^11.0.3 (#3226)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-25 13:28:48 +00:00
Meier Lukas 437ecd1023 fix(calendar): load events for all visible days of calendar month (#3216) 2025-05-25 14:51:26 +02:00
Meier Lukas 85e98d2b60 fix(boards): app select modal images rendering issue (#3218) 2025-05-25 14:51:13 +02:00
homarr-crowdin[bot] 8e24d8362e chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2025-05-25 07:49:01 +00:00
Manuel c367f8ac23 docs: add pika pods (#3215) 2025-05-24 18:53:04 +02:00
Meier Lukas c67916f72e fix(downloads): upspeed font size wrong (#3214) 2025-05-24 18:52:55 +02:00
Meier Lukas 25bd3879db fix(media-request-stats): users squeezed together (#3213) 2025-05-24 18:52:45 +02:00
Meier Lukas 939df8f6d1 feat(cluster-health): add visibility options (#3210) 2025-05-24 17:49:49 +02:00
Meier Lukas 2dc871e531 feat(downloads): add option to limit amount of items (#3205) 2025-05-24 17:49:39 +02:00
Meier Lukas f7e5e823d5 fix(visual): check for creator board permission is wrong (#3212) 2025-05-24 17:49:08 +02:00
homarr-renovate[bot] 240bf16806 chore(deps): update dependency conventional-changelog-conventionalcommits to v9 (#3151)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-24 11:17:16 +02:00
homarr-renovate[bot] 640bf7b939 fix(deps): update dependency trpc-to-openapi to ^2.3.1 (#3046)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-24 09:14:40 +00:00
homarr-renovate[bot] ec42f265a0 fix(deps): update tanstack-query monorepo to ^5.77.0 (#3204)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-24 08:22:43 +00:00
homarr-crowdin[bot] ea5a763046 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2025-05-24 00:49:31 +00:00
homarr-renovate[bot] e0a9e4f97c fix(deps): update dependency zod to ^3.25.28 (#3201)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-23 23:20:33 +00:00
homarr-renovate[bot] 581746b2c2 chore(deps): update dependency semantic-release to ^24.2.5 (#3202)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-23 22:20:55 +00:00
ManuelandMeier Lukas be8b332f94 fix: reduce logging (#3200)
Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
2025-05-23 22:36:23 +02:00
homarr-renovate[bot]andManuel 109f9e7979 fix(deps): update dependency node-cron to v4 (#3075)
Co-authored-by: Manuel <30572287+manuel-rw@users.noreply.github.com>
2025-05-23 22:20:47 +02:00
Meier Lukas 2afa9b6727 perf: cache middleware onboarding and language checks (#3197) 2025-05-23 22:20:21 +02:00
09af0a76f6 feat: allow custom protocols for app href (#2575)
Co-authored-by: Manuel <30572287+manuel-rw@users.noreply.github.com>
Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
2025-05-23 20:19:59 +00:00
Manuel 71516e02c0 ci: ignore auto gen and build files eslint (#3198) 2025-05-23 19:47:44 +00:00
Meier Lukas a5f7565468 chore(issue-template): add version 1.21.0 2025-05-23 21:19:35 +02:00
homarr-renovate[bot] 0b224e8835 fix(deps): update dependency zod to ^3.25.24 (#3195)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-23 19:18:29 +00:00
Releases Homarr f748a12b58 chore(release): 1.21.0 [skip ci] 2025-05-23 19:17:12 +00:00
homarr-releases[bot] 6b746b09b5 chore(release): automatic release v1.21.0 2025-05-23 19:15:16 +00:00
e1eda534da feat: docker widget (#2288)
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
Co-authored-by: homarr-crowdin[bot] <190541745+homarr-crowdin[bot]@users.noreply.github.com>
Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
2025-05-23 18:35:04 +00:00
Meier Lukas 09f4e6785b fix(downloads): reordering columns in widget does not work (#3194) 2025-05-23 18:33:35 +00:00
Meier Lukas 09f3989483 fix(items): resize handle overlaps header (#3193) 2025-05-23 18:33:02 +00:00
Andre Silva 4cb004fce0 fix(releases-widget): add hardcoded css classNames(#3181) 2025-05-23 18:17:06 +02:00
homarr-renovate[bot] 0ef2310776 chore(deps): update node.js to v22.16.0 (#3180)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-23 18:11:43 +02:00
homarr-update-contributors[bot] b5bc8379ae chore: update contributors (#3192)
Co-authored-by: Homarr Update Contributors <210161987+homarr-update-contributors[bot]@users.noreply.github.com>
2025-05-23 12:55:50 +00:00
homarr-renovate[bot] 43b82419e9 fix(deps): update testcontainers-node monorepo to ^10.28.0 (#3191)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-23 10:23:03 +00:00
homarr-renovate[bot] 329d4727f1 chore(deps): update dependency @vitejs/plugin-react to ^4.5.0 (#3189)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-23 01:16:09 +00:00
homarr-renovate[bot] 9840644ca5 fix(deps): update dependency zod to ^3.25.23 (#3188)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-22 23:20:48 +00:00
homarr-renovate[bot] 37d637dcae fix(deps): update dependency zod to ^3.25.21 (#3187)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-22 21:20:03 +00:00
homarr-renovate[bot] 1584114e72 fix(deps): update tanstack-query monorepo to ^5.76.2 (#3186)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-22 16:24:12 +00:00
homarr-renovate[bot] 49498c870e fix(deps): update dependency zod to ^3.25.20 (#3183)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-21 23:20:30 +00:00
homarr-renovate[bot] 5466ff5047 chore(deps): update node.js to v22.16.0 (#3179)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-21 16:25:29 +00:00
homarr-renovate[bot] 1e7b2e617b fix(deps): update dependency swagger-ui-react to ^5.22.0 (#3178)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-21 13:34:52 +00:00
homarr-renovate[bot] 371803ac50 fix(deps): update dependency zod to ^3.25.17 (#3177)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-21 12:35:21 +00:00
homarr-renovate[bot] 746ada97be chore(deps): update dependency @types/react to v19.1.5 (#3176)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-21 11:19:20 +00:00
homarr-renovate[bot] 5080f51a8d fix(deps): update dependency zod to ^3.25.16 (#3175)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-21 10:22:29 +00:00
homarr-renovate[bot] 23404a27f1 fix(deps): update dependency zod to ^3.25.14 (#3174)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-21 09:23:12 +00:00
homarr-renovate[bot] dae6dedde5 fix(deps): update dependency zod to ^3.25.13 (#3173)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-21 04:25:16 +00:00
homarr-renovate[bot] caaee503c1 fix(deps): update dependency zod to ^3.25.12 (#3172)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-21 03:15:38 +00:00
homarr-crowdin[bot] a356d61808 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2025-05-21 00:52:08 +00:00
homarr-renovate[bot] 72bcbe8eff fix(deps): update dependency zod to ^3.25.8 (#3170)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-20 23:20:46 +00:00
homarr-renovate[bot] 145365fab7 chore(deps): update dependency @types/node to ^22.15.21 (#3169)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-20 23:20:28 +00:00
homarr-renovate[bot] 8c59abdde3 fix(deps): update dependency octokit to v5 (#3156)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-20 21:36:43 +02:00
homarr-renovate[bot] 47869a3af4 chore(deps): update dependency @types/dockerode to ^3.3.39 (#3166)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-20 19:18:32 +00:00
homarr-renovate[bot] 5403b9c95e chore(deps): update dependency @types/node to ^22.15.20 (#3167)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-20 18:27:17 +00:00
homarr-renovate[bot] 50445b560e fix(deps): update dependency octokit to ^4.1.4 (#3165)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-20 16:24:19 +00:00
homarr-renovate[bot] 18c465e81e fix(deps): update testcontainers-node monorepo to ^10.27.0 (#3159)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-20 09:23:43 +00:00
homarr-renovate[bot] eb5d5f8260 fix(deps): update dependency undici to v7.10.0 (#3158)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-20 08:27:45 +00:00
homarr-renovate[bot] 096d37be37 chore(deps): update dependency proxmox-api&gt;undici to v7.10.0 (#3157)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-20 08:26:49 +00:00
homarr-crowdin[bot] 279a4b6add chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2025-05-20 00:52:28 +00:00
homarr-renovate[bot] 22954b8d26 fix(deps): update dependency zod to ^3.25.7 (#3154)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-19 23:20:23 +00:00
homarr-renovate[bot] 92ebc05fbf fix(deps): update dependency zod to ^3.25.6 (#3153)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-19 22:20:45 +00:00
homarr-renovate[bot] 79755c95d3 fix(deps): update dependency zod to ^3.25.5 (#3152)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-19 21:20:22 +00:00
homarr-renovate[bot] 49b7080415 fix(deps): update dependency zod to ^3.25.4 (#3150)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-19 20:22:49 +00:00
homarr-renovate[bot] 5b9f75eb45 chore(deps): update vitest monorepo to ^3.1.4 (#3149)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-19 17:20:34 +00:00
homarr-renovate[bot] 6e2aa87102 fix(deps): update dependency zod to ^3.25.3 (#3148)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-19 16:25:04 +00:00
homarr-renovate[bot] 17fbb0fc41 chore(deps): update dependency prettier-plugin-packagejson to ^2.5.14 (#3147)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-19 12:36:05 +00:00
homarr-renovate[bot] 28be77b9c3 chore(deps): update dependency @types/node to ^22.15.19 (#3145)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-19 01:18:27 +00:00
homarr-crowdin[bot] adddae6430 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2025-05-18 08:06:41 +00:00
Meier Lukas ef540e980f fix: esbuild not part of dependencies (#3139) 2025-05-17 20:04:05 +02:00
homarr-renovate[bot] 15675d95bd chore(deps): update dependency semantic-release to ^24.2.4 (#3134)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-17 01:13:09 +00:00
homarr-crowdin[bot] 16e2f3f1e4 chore(lang): updated translations from crowdin
Co-authored-by: Crowdin Homarr <190541745+homarr-crowdin[bot]@users.noreply.github.com>
2025-05-17 00:50:13 +00:00
homarr-renovate[bot] bf6b7912f9 chore(deps): update dependency eslint to ^9.27.0 (#3128)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-16 20:24:10 +00:00
homarr-renovate[bot] ee8870b66b fix(deps): update dependency @tabler/icons-react to ^3.33.0 (#3132)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-16 20:23:22 +00:00
Meier Lukas c6464e582e chore(issue-template): add version 1.20.0 2025-05-16 21:27:28 +02:00
homarr-renovate[bot] 886e95d517 fix(deps): update dependency zod-validation-error to ^3.4.1 (#3127)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2025-05-16 19:19:41 +00:00
137 changed files with 9574 additions and 2469 deletions

No files matched your search

+2
View File
@@ -31,6 +31,8 @@ body:
label: Version label: Version
description: What version of Homarr are you running? description: What version of Homarr are you running?
options: options:
- 1.21.0
- 1.20.0
- 1.19.1 - 1.19.1
- 1.19.0 - 1.19.0
- 1.18.0 - 1.18.0
+1 -1
View File
@@ -1 +1 @@
22.15.1 22.16.0
+36
View File
@@ -1,3 +1,39 @@
## [1.21.0](https://github.com/homarr-labs/homarr/compare/v1.20.0...v1.21.0) (2025-05-23)
### Features
* docker widget ([#2288](https://github.com/homarr-labs/homarr/issues/2288)) ([e1eda53](https://github.com/homarr-labs/homarr/commit/e1eda534da6d97655546f3140f9e36eca8817db3))
### Bug Fixes
* **deps:** update dependency @tabler/icons-react to ^3.33.0 ([#3132](https://github.com/homarr-labs/homarr/issues/3132)) ([ee8870b](https://github.com/homarr-labs/homarr/commit/ee8870b66bbcb8eeeef359ece9391a496198be0d))
* **deps:** update dependency octokit to ^4.1.4 ([#3165](https://github.com/homarr-labs/homarr/issues/3165)) ([50445b5](https://github.com/homarr-labs/homarr/commit/50445b560edc3af2631f8d8d9aa81f3387d848f7))
* **deps:** update dependency octokit to v5 ([#3156](https://github.com/homarr-labs/homarr/issues/3156)) ([8c59abd](https://github.com/homarr-labs/homarr/commit/8c59abdde3d8034f22a2b926b3291b55a0d492ea))
* **deps:** update dependency swagger-ui-react to ^5.22.0 ([#3178](https://github.com/homarr-labs/homarr/issues/3178)) ([1e7b2e6](https://github.com/homarr-labs/homarr/commit/1e7b2e617b1437f0f98bc791e763bc49b6589b9e))
* **deps:** update dependency undici to v7.10.0 ([#3158](https://github.com/homarr-labs/homarr/issues/3158)) ([eb5d5f8](https://github.com/homarr-labs/homarr/commit/eb5d5f8260cc9795806ecdb56fbb3f8d19858ed7))
* **deps:** update dependency zod to ^3.25.12 ([#3172](https://github.com/homarr-labs/homarr/issues/3172)) ([caaee50](https://github.com/homarr-labs/homarr/commit/caaee503c128ff2a0b2a7de7a7c353484e4741a5))
* **deps:** update dependency zod to ^3.25.13 ([#3173](https://github.com/homarr-labs/homarr/issues/3173)) ([dae6ded](https://github.com/homarr-labs/homarr/commit/dae6dedde544bf28fcdf87c71a9d585078527b82))
* **deps:** update dependency zod to ^3.25.14 ([#3174](https://github.com/homarr-labs/homarr/issues/3174)) ([23404a2](https://github.com/homarr-labs/homarr/commit/23404a27f1a9dfec4e9126750f8d97e7c5eda572))
* **deps:** update dependency zod to ^3.25.16 ([#3175](https://github.com/homarr-labs/homarr/issues/3175)) ([5080f51](https://github.com/homarr-labs/homarr/commit/5080f51a8dbe1b82571f356f7ae29ed7be69e18e))
* **deps:** update dependency zod to ^3.25.17 ([#3177](https://github.com/homarr-labs/homarr/issues/3177)) ([371803a](https://github.com/homarr-labs/homarr/commit/371803ac509efd246367c812a6c0143e7aeda03f))
* **deps:** update dependency zod to ^3.25.20 ([#3183](https://github.com/homarr-labs/homarr/issues/3183)) ([49498c8](https://github.com/homarr-labs/homarr/commit/49498c870e494b417e6c63d8547a4c0ffd93768b))
* **deps:** update dependency zod to ^3.25.21 ([#3187](https://github.com/homarr-labs/homarr/issues/3187)) ([37d637d](https://github.com/homarr-labs/homarr/commit/37d637dcae6cbf62efda25a8dc01eedba66f2c74))
* **deps:** update dependency zod to ^3.25.23 ([#3188](https://github.com/homarr-labs/homarr/issues/3188)) ([9840644](https://github.com/homarr-labs/homarr/commit/9840644ca50d3157223e7da0cf895f2e750afc58))
* **deps:** update dependency zod to ^3.25.3 ([#3148](https://github.com/homarr-labs/homarr/issues/3148)) ([6e2aa87](https://github.com/homarr-labs/homarr/commit/6e2aa87102b72319236483b9a1d3e5ddd6fe2c82))
* **deps:** update dependency zod to ^3.25.4 ([#3150](https://github.com/homarr-labs/homarr/issues/3150)) ([49b7080](https://github.com/homarr-labs/homarr/commit/49b7080415aaeee576507d48e8cda18acc9943a8))
* **deps:** update dependency zod to ^3.25.5 ([#3152](https://github.com/homarr-labs/homarr/issues/3152)) ([79755c9](https://github.com/homarr-labs/homarr/commit/79755c95d3cf58680e434f0113c130db9f649d96))
* **deps:** update dependency zod to ^3.25.6 ([#3153](https://github.com/homarr-labs/homarr/issues/3153)) ([92ebc05](https://github.com/homarr-labs/homarr/commit/92ebc05fbfded6d20d242ad477cb0dc30243e8cc))
* **deps:** update dependency zod to ^3.25.7 ([#3154](https://github.com/homarr-labs/homarr/issues/3154)) ([22954b8](https://github.com/homarr-labs/homarr/commit/22954b8d2637cdea9a6502cab2d3d40359fa098f))
* **deps:** update dependency zod to ^3.25.8 ([#3170](https://github.com/homarr-labs/homarr/issues/3170)) ([72bcbe8](https://github.com/homarr-labs/homarr/commit/72bcbe8effe47fdfb6a94de8defc0d3c12e7c754))
* **deps:** update dependency zod-validation-error to ^3.4.1 ([#3127](https://github.com/homarr-labs/homarr/issues/3127)) ([886e95d](https://github.com/homarr-labs/homarr/commit/886e95d51714ce20e03d32b4c2cfb673e7e4c218))
* **deps:** update tanstack-query monorepo to ^5.76.2 ([#3186](https://github.com/homarr-labs/homarr/issues/3186)) ([1584114](https://github.com/homarr-labs/homarr/commit/1584114e72246a018b9f49a859e49f7fb985009d))
* **deps:** update testcontainers-node monorepo to ^10.27.0 ([#3159](https://github.com/homarr-labs/homarr/issues/3159)) ([18c465e](https://github.com/homarr-labs/homarr/commit/18c465e81e92cf58b7e32bcb70f1ab404a03a135))
* **deps:** update testcontainers-node monorepo to ^10.28.0 ([#3191](https://github.com/homarr-labs/homarr/issues/3191)) ([43b8241](https://github.com/homarr-labs/homarr/commit/43b82419e9396f0b80bafa0a707d575c3732dc5b))
* **downloads:** reordering columns in widget does not work ([#3194](https://github.com/homarr-labs/homarr/issues/3194)) ([09f4e67](https://github.com/homarr-labs/homarr/commit/09f4e6785b2ce38da3b52003e9c9300cdd0feb85))
* esbuild not part of dependencies ([#3139](https://github.com/homarr-labs/homarr/issues/3139)) ([ef540e9](https://github.com/homarr-labs/homarr/commit/ef540e980f90f730020ef081dd105e33b0671232))
* **items:** resize handle overlaps header ([#3193](https://github.com/homarr-labs/homarr/issues/3193)) ([09f3989](https://github.com/homarr-labs/homarr/commit/09f398948348fb402600506571a967ba405fbafb))
* **releases-widget:** add hardcoded css classNames([#3181](https://github.com/homarr-labs/homarr/issues/3181)) ([4cb004f](https://github.com/homarr-labs/homarr/commit/4cb004fce0750da339f603b944de55135faa4bfa))
## [1.20.0](https://github.com/homarr-labs/homarr/compare/v1.19.1...v1.20.0) (2025-05-16) ## [1.20.0](https://github.com/homarr-labs/homarr/compare/v1.19.1...v1.20.0) (2025-05-16)
### Features ### Features
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:22.15.1-alpine AS base FROM node:22.16.0-alpine AS base
FROM base AS builder FROM base AS builder
RUN apk add --no-cache libc6-compat RUN apk add --no-cache libc6-compat
+41 -4
View File
@@ -17,7 +17,7 @@ const withNextIntl = createNextIntlPlugin({
requestConfig: "../../packages/translation/src/request.ts", requestConfig: "../../packages/translation/src/request.ts",
}); });
interface WebpackConfig { interface _WebpackConfig {
module: { module: {
rules: { rules: {
test: RegExp; test: RegExp;
@@ -32,7 +32,7 @@ const nextConfig: NextConfig = {
/** We already do linting and typechecking as separate tasks in CI */ /** We already do linting and typechecking as separate tasks in CI */
eslint: { ignoreDuringBuilds: true }, eslint: { ignoreDuringBuilds: true },
typescript: { ignoreBuildErrors: true }, typescript: { ignoreBuildErrors: true },
webpack: (config: WebpackConfig, { isServer }) => { /*webpack: (config: WebpackConfig, { isServer }) => {
if (isServer) { if (isServer) {
config.module.rules.push({ config.module.rules.push({
test: /\.node$/, test: /\.node$/,
@@ -41,14 +41,51 @@ const nextConfig: NextConfig = {
} }
return config; return config;
}, },*/
experimental: { experimental: {
optimizePackageImports: ["@mantine/core", "@mantine/hooks", "@tabler/icons-react"], optimizePackageImports: ["@mantine/core", "@mantine/hooks", "@tabler/icons-react"],
}, },
transpilePackages: ["@homarr/ui", "@homarr/notifications", "@homarr/modals", "@homarr/spotlight", "@homarr/widgets"], serverExternalPackages: [
"dockerode",
"@kubernetes/client-node",
"@ctrl/deluge",
"@ctrl/qbittorrent",
"@ctrl/transmission",
"node-ical",
"tsdav",
"proxmox-api",
"@jellyfin/sdk",
],
images: { images: {
domains: ["cdn.jsdelivr.net"], domains: ["cdn.jsdelivr.net"],
}, },
// eslint-disable-next-line @typescript-eslint/require-await,no-restricted-syntax
async headers() {
return [
{
source: "/(.*)", // Apply CSP to all routes
headers: [
{
key: "Content-Security-Policy",
value: `
default-src 'self';
script-src * 'unsafe-inline' 'unsafe-eval';
base-uri 'self';
connect-src *;
style-src 'self' 'unsafe-inline';
frame-ancestors *;
frame-src *;
form-action 'self';
img-src * data:;
font-src * data:;
`
.replace(/\s{2,}/g, " ")
.trim(),
},
],
},
];
},
}; };
// Skip transform is used because of webpack loader, without it for example 'Tooltip.Floating' will not work and show an error // Skip transform is used because of webpack loader, without it for example 'Tooltip.Floating' will not work and show an error
+20 -20
View File
@@ -48,21 +48,21 @@
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@homarr/widgets": "workspace:^0.1.0", "@homarr/widgets": "workspace:^0.1.0",
"@mantine/colors-generator": "^8.0.1", "@mantine/colors-generator": "^8.0.2",
"@mantine/core": "^8.0.1", "@mantine/core": "^8.0.2",
"@mantine/dropzone": "^8.0.1", "@mantine/dropzone": "^8.0.2",
"@mantine/hooks": "^8.0.1", "@mantine/hooks": "^8.0.2",
"@mantine/modals": "^8.0.1", "@mantine/modals": "^8.0.2",
"@mantine/tiptap": "^8.0.1", "@mantine/tiptap": "^8.0.2",
"@million/lint": "1.0.14", "@million/lint": "1.0.14",
"@tabler/icons-react": "^3.31.0", "@tabler/icons-react": "^3.33.0",
"@tanstack/react-query": "^5.76.1", "@tanstack/react-query": "^5.77.2",
"@tanstack/react-query-devtools": "^5.76.1", "@tanstack/react-query-devtools": "^5.77.2",
"@tanstack/react-query-next-experimental": "^5.76.1", "@tanstack/react-query-next-experimental": "^5.77.2",
"@trpc/client": "^11.1.2", "@trpc/client": "^11.1.3",
"@trpc/next": "^11.1.2", "@trpc/next": "^11.1.3",
"@trpc/react-query": "^11.1.2", "@trpc/react-query": "^11.1.3",
"@trpc/server": "^11.1.2", "@trpc/server": "^11.1.3",
"@xterm/addon-canvas": "^0.7.0", "@xterm/addon-canvas": "^0.7.0",
"@xterm/addon-fit": "0.10.0", "@xterm/addon-fit": "0.10.0",
"@xterm/xterm": "^5.5.0", "@xterm/xterm": "^5.5.0",
@@ -72,7 +72,7 @@
"dotenv": "^16.5.0", "dotenv": "^16.5.0",
"flag-icons": "^7.3.2", "flag-icons": "^7.3.2",
"glob": "^11.0.2", "glob": "^11.0.2",
"jotai": "^2.12.4", "jotai": "^2.12.5",
"mantine-react-table": "2.0.0-beta.9", "mantine-react-table": "2.0.0-beta.9",
"next": "15.3.2", "next": "15.3.2",
"postcss-preset-mantine": "^1.17.0", "postcss-preset-mantine": "^1.17.0",
@@ -83,22 +83,22 @@
"react-simple-code-editor": "^0.14.1", "react-simple-code-editor": "^0.14.1",
"sass": "^1.89.0", "sass": "^1.89.0",
"superjson": "2.2.2", "superjson": "2.2.2",
"swagger-ui-react": "^5.21.0", "swagger-ui-react": "^5.22.0",
"use-deep-compare-effect": "^1.8.1", "use-deep-compare-effect": "^1.8.1",
"zod": "^3.24.4" "zod": "^3.25.30"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/chroma-js": "3.1.1", "@types/chroma-js": "3.1.1",
"@types/node": "^22.15.18", "@types/node": "^22.15.21",
"@types/prismjs": "^1.26.5", "@types/prismjs": "^1.26.5",
"@types/react": "19.1.4", "@types/react": "19.1.6",
"@types/react-dom": "19.1.5", "@types/react-dom": "19.1.5",
"@types/swagger-ui-react": "^5.18.0", "@types/swagger-ui-react": "^5.18.0",
"concurrently": "^9.1.2", "concurrently": "^9.1.2",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"node-loader": "^2.1.0", "node-loader": "^2.1.0",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"typescript": "^5.8.3" "typescript": "^5.8.3"
@@ -1,6 +1,5 @@
"use client"; "use client";
import type { MouseEvent } from "react";
import { useCallback, useEffect } from "react"; import { useCallback, useEffect } from "react";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
@@ -204,17 +203,22 @@ const SelectBoardsMenu = () => {
); );
}; };
const anchorSelector = "a[href]:not([target='_blank'])";
const usePreventLeaveWithDirty = (isDirty: boolean) => { const usePreventLeaveWithDirty = (isDirty: boolean) => {
const t = useI18n(); const t = useI18n();
const { openConfirmModal } = useConfirmModal(); const { openConfirmModal } = useConfirmModal();
const router = useRouter(); const router = useRouter();
useEffect(() => { useEffect(() => {
const handleClick = (event: MouseEvent<HTMLElement>) => { if (!isDirty) return;
const handleClick = (event: Event) => {
const target = (event.target as HTMLElement).closest("a"); const target = (event.target as HTMLElement).closest("a");
if (!target) return; if (!target) {
if (!isDirty) return; console.warn("No anchor element found for click event", event);
return;
}
event.preventDefault(); event.preventDefault();
@@ -231,33 +235,29 @@ const usePreventLeaveWithDirty = (isDirty: boolean) => {
}; };
const handlePopState = (event: Event) => { const handlePopState = (event: Event) => {
if (isDirty) { window.history.pushState(null, document.title, window.location.href);
window.history.pushState(null, document.title, window.location.href); event.preventDefault();
event.preventDefault();
} else {
window.history.back();
}
}; };
const handleBeforeUnload = (event: BeforeUnloadEvent) => { const handleBeforeUnload = (event: BeforeUnloadEvent) => {
if (!isDirty) return;
if (env.NODE_ENV === "development") return; // Allow to reload in development if (env.NODE_ENV === "development") return; // Allow to reload in development
event.preventDefault(); event.preventDefault();
event.returnValue = true; event.returnValue = true;
}; };
document.querySelectorAll("a").forEach((link) => { const anchors = document.querySelectorAll(anchorSelector);
link.addEventListener("click", handleClick as never); anchors.forEach((link) => {
link.addEventListener("click", handleClick);
}); });
window.addEventListener("popstate", handlePopState); window.addEventListener("popstate", handlePopState);
window.addEventListener("beforeunload", handleBeforeUnload); window.addEventListener("beforeunload", handleBeforeUnload);
return () => { return () => {
document.querySelectorAll("a").forEach((link) => { anchors.forEach((link) => {
link.removeEventListener("click", handleClick as never); link.removeEventListener("click", handleClick);
window.removeEventListener("popstate", handlePopState);
}); });
window.removeEventListener("popstate", handlePopState);
window.removeEventListener("beforeunload", handleBeforeUnload); window.removeEventListener("beforeunload", handleBeforeUnload);
}; };
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -17,6 +17,7 @@ import type { RouterOutputs } from "@homarr/api";
import { clientApi } from "@homarr/api/client"; import { clientApi } from "@homarr/api/client";
import { useTimeAgo } from "@homarr/common"; import { useTimeAgo } from "@homarr/common";
import type { ContainerState } from "@homarr/docker"; import type { ContainerState } from "@homarr/docker";
import { containerStateColorMap } from "@homarr/docker/shared";
import { useModalAction } from "@homarr/modals"; import { useModalAction } from "@homarr/modals";
import { AddDockerAppToHomarr } from "@homarr/modals-collection"; import { AddDockerAppToHomarr } from "@homarr/modals-collection";
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications"; import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
@@ -244,21 +245,11 @@ const ContainerActionBarButton = (props: ContainerActionBarButtonProps) => {
); );
}; };
const containerStates = {
created: "cyan",
running: "green",
paused: "yellow",
restarting: "orange",
exited: "red",
removing: "pink",
dead: "dark",
} satisfies Record<ContainerState, MantineColor>;
const ContainerStateBadge = ({ state }: { state: ContainerState }) => { const ContainerStateBadge = ({ state }: { state: ContainerState }) => {
const t = useScopedI18n("docker.field.state.option"); const t = useScopedI18n("docker.field.state.option");
return ( return (
<Badge size="lg" radius="sm" variant="light" w={120} color={containerStates[state]}> <Badge size="lg" radius="sm" variant="light" w={120} color={containerStateColorMap[state]}>
{t(state)} {t(state)}
</Badge> </Badge>
); );
@@ -125,8 +125,8 @@ const InnerContent = ({ item, ...dimensions }: InnerContentProps) => {
setOptions={(partialNewOptions) => setOptions={(partialNewOptions) =>
updateOptions({ updateOptions({
newOptions: { newOptions: {
...partialNewOptions.newOptions,
...options, ...options,
...partialNewOptions.newOptions,
}, },
}) })
} }
+17 -6
View File
@@ -5,25 +5,36 @@ import SuperJSON from "superjson";
import type { AppRouter } from "@homarr/api"; import type { AppRouter } from "@homarr/api";
import { createHeadersCallbackForSource, getTrpcUrl } from "@homarr/api/shared"; import { createHeadersCallbackForSource, getTrpcUrl } from "@homarr/api/shared";
import { localeCookieKey } from "@homarr/definitions";
import type { SupportedLanguage } from "@homarr/translation";
import { supportedLanguages } from "@homarr/translation";
import { createI18nMiddleware } from "@homarr/translation/middleware"; import { createI18nMiddleware } from "@homarr/translation/middleware";
export async function middleware(request: NextRequest) { let isOnboardingFinished = false;
// fetch api does not work because window is not defined and we need to construct the url from the headers
// In next 15 we will be able to use node apis and such the db directly
const culture = await serverFetchApi.serverSettings.getCulture.query();
export async function middleware(request: NextRequest) {
// Redirect to onboarding if it's not finished yet // Redirect to onboarding if it's not finished yet
const pathname = request.nextUrl.pathname; const pathname = request.nextUrl.pathname;
if (!pathname.endsWith("/init")) {
if (!isOnboardingFinished && !pathname.endsWith("/init")) {
const currentOnboardingStep = await serverFetchApi.onboard.currentStep.query(); const currentOnboardingStep = await serverFetchApi.onboard.currentStep.query();
if (currentOnboardingStep.current !== "finish") { if (currentOnboardingStep.current !== "finish") {
return NextResponse.redirect(new URL("/init", request.url)); return NextResponse.redirect(new URL("/init", request.url));
} }
isOnboardingFinished = true;
}
// Only run this if the user has not already configured their language
const currentLocale = request.cookies.get(localeCookieKey)?.value;
let defaultLocale: SupportedLanguage = "en";
if (!currentLocale || !supportedLanguages.includes(currentLocale as SupportedLanguage)) {
defaultLocale = await serverFetchApi.serverSettings.getCulture.query().then((culture) => culture.defaultLocale);
} }
// We don't want to fallback to accept-language header so we clear it // We don't want to fallback to accept-language header so we clear it
request.headers.set("accept-language", ""); request.headers.set("accept-language", "");
const next = createI18nMiddleware(culture.defaultLocale); const next = createI18nMiddleware(defaultLocale);
return next(request); return next(request);
} }
+6
View File
@@ -6,6 +6,12 @@
--gridstack-cell-size: 0; --gridstack-cell-size: 0;
} }
.ui-resizable-handle {
// Override default z-index of 100 to prevent it from being on top of the header.
// See https://github.com/homarr-labs/homarr/issues/1999
z-index: 1 !important;
}
.grid-stack-placeholder > .placeholder-content { .grid-stack-placeholder > .placeholder-content {
background-color: rgb(248, 249, 250) !important; background-color: rgb(248, 249, 250) !important;
border-radius: 12px; border-radius: 12px;
+5 -4
View File
@@ -10,7 +10,7 @@
"main": "./src/main.ts", "main": "./src/main.ts",
"types": "./src/main.ts", "types": "./src/main.ts",
"scripts": { "scripts": {
"build": "esbuild src/main.ts --bundle --platform=node --loader:.scss=text --external:@opentelemetry/api --external:deasync --outfile=tasks.cjs", "build": "esbuild src/main.ts --bundle --platform=node --loader:.scss=text --external:*.node --external:@opentelemetry/api --external:deasync --outfile=tasks.cjs",
"clean": "rm -rf .turbo node_modules", "clean": "rm -rf .turbo node_modules",
"dev": "pnpm with-env tsx ./src/main.ts", "dev": "pnpm with-env tsx ./src/main.ts",
"format": "prettier --check . --ignore-path ../../.gitignore", "format": "prettier --check . --ignore-path ../../.gitignore",
@@ -38,15 +38,16 @@
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"dotenv": "^16.5.0", "dotenv": "^16.5.0",
"superjson": "2.2.2", "superjson": "2.2.2",
"undici": "7.9.0" "undici": "7.10.0"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/node": "^22.15.18", "@types/node": "^22.15.21",
"dotenv-cli": "^8.0.0", "dotenv-cli": "^8.0.0",
"eslint": "^9.26.0", "esbuild": "^0.25.5",
"eslint": "^9.27.0",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"tsx": "4.19.4", "tsx": "4.19.4",
"typescript": "^5.8.3" "typescript": "^5.8.3"
+2 -1
View File
@@ -34,7 +34,8 @@
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/ws": "^8.18.1", "@types/ws": "^8.18.1",
"eslint": "^9.26.0", "esbuild": "^0.25.5",
"eslint": "^9.27.0",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
+3 -1
View File
@@ -120,4 +120,6 @@ You can also support us by helping with [translating the entire project](https:/
Thanks to your generous sponsors we can continue to build Homarr. Check them out for high quality and easy to use development tools. Thanks to your generous sponsors we can continue to build Homarr. Check them out for high quality and easy to use development tools.
Feel free to contact us at homarr-labs@proton.me if you wish to become a sponsor. Feel free to contact us at homarr-labs@proton.me if you wish to become a sponsor.
[![Covered by Argos Visual Testing](https://argos-ci.com/badge-large.svg)](https://argos-ci.com?utm_source=%5Bhomarr%5D&utm_campaign=oss) [![Covered by Argos Visual Testing](https://argos-ci.com/badge-large.svg)](https://argos-ci.com?utm_source=%5Bhomarr%5D&utm_campaign=oss) \
[![Supported by PikaPods](https://www.pikapods.com/static/run-button.svg)](https://www.pikapods.com/pods?run=homarr-v1)
+11 -11
View File
@@ -1,6 +1,6 @@
{ {
"name": "homarr", "name": "homarr",
"version": "1.20.0", "version": "1.21.0",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "cross-env CI=true turbo build", "build": "cross-env CI=true turbo build",
@@ -35,27 +35,27 @@
"@semantic-release/changelog": "^6.0.3", "@semantic-release/changelog": "^6.0.3",
"@semantic-release/commit-analyzer": "^13.0.1", "@semantic-release/commit-analyzer": "^13.0.1",
"@semantic-release/git": "^10.0.1", "@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^11.0.2", "@semantic-release/github": "^11.0.3",
"@semantic-release/npm": "^12.0.1", "@semantic-release/npm": "^12.0.1",
"@semantic-release/release-notes-generator": "^14.0.3", "@semantic-release/release-notes-generator": "^14.0.3",
"@turbo/gen": "^2.5.3", "@turbo/gen": "^2.5.3",
"@vitejs/plugin-react": "^4.4.1", "@vitejs/plugin-react": "^4.5.0",
"@vitest/coverage-v8": "^3.1.3", "@vitest/coverage-v8": "^3.1.4",
"@vitest/ui": "^3.1.3", "@vitest/ui": "^3.1.4",
"conventional-changelog-conventionalcommits": "^8.0.0", "conventional-changelog-conventionalcommits": "^9.0.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"jsdom": "^26.1.0", "jsdom": "^26.1.0",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"semantic-release": "^24.2.3", "semantic-release": "^24.2.5",
"testcontainers": "^10.26.0", "testcontainers": "^10.28.0",
"turbo": "^2.5.3", "turbo": "^2.5.3",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"vite-tsconfig-paths": "^5.1.4", "vite-tsconfig-paths": "^5.1.4",
"vitest": "^3.1.3" "vitest": "^3.1.4"
}, },
"packageManager": "pnpm@10.11.0", "packageManager": "pnpm@10.11.0",
"engines": { "engines": {
"node": ">=22.15.1" "node": ">=22.16.0"
}, },
"pnpm": { "pnpm": {
"onlyBuiltDependencies": [ "onlyBuiltDependencies": [
@@ -70,7 +70,7 @@
"tree-sitter-json" "tree-sitter-json"
], ],
"overrides": { "overrides": {
"proxmox-api>undici": "7.9.0" "proxmox-api>undici": "7.10.0"
}, },
"allowUnusedPatches": true, "allowUnusedPatches": true,
"ignoredBuiltDependencies": [ "ignoredBuiltDependencies": [
+1 -1
View File
@@ -32,7 +32,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+8 -8
View File
@@ -41,24 +41,24 @@
"@homarr/server-settings": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@kubernetes/client-node": "^1.2.0", "@kubernetes/client-node": "^1.2.0",
"@tanstack/react-query": "^5.76.1", "@tanstack/react-query": "^5.77.2",
"@trpc/client": "^11.1.2", "@trpc/client": "^11.1.3",
"@trpc/react-query": "^11.1.2", "@trpc/react-query": "^11.1.3",
"@trpc/server": "^11.1.2", "@trpc/server": "^11.1.3",
"@trpc/tanstack-react-query": "^11.1.2", "@trpc/tanstack-react-query": "^11.1.3",
"lodash.clonedeep": "^4.5.0", "lodash.clonedeep": "^4.5.0",
"next": "15.3.2", "next": "15.3.2",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"superjson": "2.2.2", "superjson": "2.2.2",
"trpc-to-openapi": "^2.2.0", "trpc-to-openapi": "^2.3.1",
"zod": "^3.24.4" "zod": "^3.25.30"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
+25 -46
View File
@@ -1,52 +1,31 @@
import { apiKeysRouter } from "./router/apiKeys"; import { lazy } from "@trpc/server";
import { appRouter as innerAppRouter } from "./router/app";
import { boardRouter } from "./router/board";
import { certificateRouter } from "./router/certificates/certificate-router";
import { cronJobsRouter } from "./router/cron-jobs";
import { dockerRouter } from "./router/docker/docker-router";
import { groupRouter } from "./router/group";
import { homeRouter } from "./router/home";
import { iconsRouter } from "./router/icons";
import { importRouter } from "./router/import/import-router";
import { integrationRouter } from "./router/integration/integration-router";
import { inviteRouter } from "./router/invite";
import { kubernetesRouter } from "./router/kubernetes/router/kubernetes-router";
import { locationRouter } from "./router/location";
import { logRouter } from "./router/log";
import { mediaRouter } from "./router/medias/media-router";
import { onboardRouter } from "./router/onboard/onboard-router";
import { searchEngineRouter } from "./router/search-engine/search-engine-router";
import { sectionRouter } from "./router/section/section-router";
import { serverSettingsRouter } from "./router/serverSettings";
import { updateCheckerRouter } from "./router/update-checker";
import { userRouter } from "./router/user";
import { widgetRouter } from "./router/widgets";
import { createTRPCRouter } from "./trpc"; import { createTRPCRouter } from "./trpc";
export const appRouter = createTRPCRouter({ export const appRouter = createTRPCRouter({
user: userRouter, user: lazy(() => import("./router/user").then((mod) => mod.userRouter)),
group: groupRouter, group: lazy(() => import("./router/group").then((mod) => mod.groupRouter)),
invite: inviteRouter, invite: lazy(() => import("./router/invite").then((mod) => mod.inviteRouter)),
integration: integrationRouter, integration: lazy(() => import("./router/integration/integration-router").then((mod) => mod.integrationRouter)),
board: boardRouter, board: lazy(() => import("./router/board").then((mod) => mod.boardRouter)),
section: sectionRouter, section: lazy(() => import("./router/section/section-router").then((mod) => mod.sectionRouter)),
app: innerAppRouter, app: lazy(() => import("./router/app").then((mod) => mod.appRouter)),
searchEngine: searchEngineRouter, searchEngine: lazy(() => import("./router/search-engine/search-engine-router").then((mod) => mod.searchEngineRouter)),
widget: widgetRouter, widget: lazy(() => import("./router/widgets").then((mod) => mod.widgetRouter)),
location: locationRouter, location: lazy(() => import("./router/location").then((mod) => mod.locationRouter)),
log: logRouter, log: lazy(() => import("./router/log").then((mod) => mod.logRouter)),
icon: iconsRouter, icon: lazy(() => import("./router/icons").then((mod) => mod.iconsRouter)),
import: importRouter, import: lazy(() => import("./router/import/import-router").then((mod) => mod.importRouter)),
onboard: onboardRouter, onboard: lazy(() => import("./router/onboard/onboard-router").then((mod) => mod.onboardRouter)),
home: homeRouter, home: lazy(() => import("./router/home").then((mod) => mod.homeRouter)),
docker: dockerRouter, docker: lazy(() => import("./router/docker/docker-router").then((mod) => mod.dockerRouter)),
kubernetes: kubernetesRouter, kubernetes: lazy(() => import("./router/kubernetes/router/kubernetes-router").then((mod) => mod.kubernetesRouter)),
serverSettings: serverSettingsRouter, serverSettings: lazy(() => import("./router/serverSettings").then((mod) => mod.serverSettingsRouter)),
cronJobs: cronJobsRouter, cronJobs: lazy(() => import("./router/cron-jobs").then((mod) => mod.cronJobsRouter)),
apiKeys: apiKeysRouter, apiKeys: lazy(() => import("./router/apiKeys").then((mod) => mod.apiKeysRouter)),
media: mediaRouter, media: lazy(() => import("./router/medias/media-router").then((mod) => mod.mediaRouter)),
updateChecker: updateCheckerRouter, updateChecker: lazy(() => import("./router/update-checker").then((mod) => mod.updateCheckerRouter)),
certificates: certificateRouter, certificates: lazy(() => import("./router/certificates/certificate-router").then((mod) => mod.certificateRouter)),
}); });
// export type definition of API // export type definition of API
+31 -83
View File
@@ -1,90 +1,48 @@
import { TRPCError } from "@trpc/server"; import { TRPCError } from "@trpc/server";
import { observable } from "@trpc/server/observable";
import { z } from "zod"; import { z } from "zod";
import { db, like, or } from "@homarr/db"; import type { Container, ContainerState, Docker, Port } from "@homarr/docker";
import { icons } from "@homarr/db/schema";
import { DockerSingleton } from "@homarr/docker"; import { DockerSingleton } from "@homarr/docker";
import type { Container, ContainerInfo, ContainerState, Docker, Port } from "@homarr/docker"; import { dockerContainersRequestHandler } from "@homarr/request-handler/docker";
import { logger } from "@homarr/log";
import { createCacheChannel } from "@homarr/redis";
import { dockerMiddleware } from "../../middlewares/docker"; import { dockerMiddleware } from "../../middlewares/docker";
import { createTRPCRouter, permissionRequiredProcedure } from "../../trpc"; import { createTRPCRouter, permissionRequiredProcedure } from "../../trpc";
const dockerCache = createCacheChannel<{
containers: (ContainerInfo & { instance: string; iconUrl: string | null })[];
}>("docker-containers", 5 * 60 * 1000);
export const dockerRouter = createTRPCRouter({ export const dockerRouter = createTRPCRouter({
getContainers: permissionRequiredProcedure getContainers: permissionRequiredProcedure
.requiresPermission("admin") .requiresPermission("admin")
.concat(dockerMiddleware()) .concat(dockerMiddleware())
.query(async () => { .query(async () => {
const result = await dockerCache const innerHandler = dockerContainersRequestHandler.handler({});
.consumeAsync(async () => { const result = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false });
const dockerInstances = DockerSingleton.getInstances();
const containers = await Promise.all(
// Return all the containers of all the instances into only one item
dockerInstances.map(({ instance, host: key }) =>
instance.listContainers({ all: true }).then((containers) =>
containers.map((container) => ({
...container,
instance: key,
})),
),
),
).then((containers) => containers.flat());
const extractImage = (container: ContainerInfo) => container.Image.split("/").at(-1)?.split(":").at(0) ?? "";
const likeQueries = containers.map((container) => like(icons.name, `%${extractImage(container)}%`));
const dbIcons =
likeQueries.length >= 1
? await db.query.icons.findMany({
where: or(...likeQueries),
})
: [];
return {
containers: containers.map((container) => ({
...container,
iconUrl:
dbIcons.find((icon) => {
const extractedImage = extractImage(container);
if (!extractedImage) return false;
return icon.name.toLowerCase().includes(extractedImage.toLowerCase());
})?.url ?? null,
})),
};
})
.catch((error) => {
logger.error(error);
return {
isError: true,
error: error as unknown,
};
});
if ("isError" in result) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "An error occurred while fetching the containers",
cause: result.error,
});
}
const { data, timestamp } = result; const { data, timestamp } = result;
return { return {
containers: sanitizeContainers(data.containers), containers: data satisfies DockerContainer[],
timestamp, timestamp,
}; };
}), }),
subscribeContainers: permissionRequiredProcedure
.requiresPermission("admin")
.concat(dockerMiddleware())
.subscription(() => {
return observable<DockerContainer[]>((emit) => {
const innerHandler = dockerContainersRequestHandler.handler({});
const unsubscribe = innerHandler.subscribe((data) => {
emit.next(data);
});
return unsubscribe;
});
}),
invalidate: permissionRequiredProcedure invalidate: permissionRequiredProcedure
.requiresPermission("admin") .requiresPermission("admin")
.concat(dockerMiddleware()) .concat(dockerMiddleware())
.mutation(async () => { .mutation(async () => {
await dockerCache.invalidateAsync(); const innerHandler = dockerContainersRequestHandler.handler({});
return; await innerHandler.invalidateAsync();
}), }),
startAll: permissionRequiredProcedure startAll: permissionRequiredProcedure
.requiresPermission("admin") .requiresPermission("admin")
@@ -98,7 +56,8 @@ export const dockerRouter = createTRPCRouter({
}), }),
); );
await dockerCache.invalidateAsync(); const innerHandler = dockerContainersRequestHandler.handler({});
await innerHandler.invalidateAsync();
}), }),
stopAll: permissionRequiredProcedure stopAll: permissionRequiredProcedure
.requiresPermission("admin") .requiresPermission("admin")
@@ -112,7 +71,8 @@ export const dockerRouter = createTRPCRouter({
}), }),
); );
await dockerCache.invalidateAsync(); const innerHandler = dockerContainersRequestHandler.handler({});
await innerHandler.invalidateAsync();
}), }),
restartAll: permissionRequiredProcedure restartAll: permissionRequiredProcedure
.requiresPermission("admin") .requiresPermission("admin")
@@ -126,7 +86,8 @@ export const dockerRouter = createTRPCRouter({
}), }),
); );
await dockerCache.invalidateAsync(); const innerHandler = dockerContainersRequestHandler.handler({});
await innerHandler.invalidateAsync();
}), }),
removeAll: permissionRequiredProcedure removeAll: permissionRequiredProcedure
.requiresPermission("admin") .requiresPermission("admin")
@@ -140,7 +101,8 @@ export const dockerRouter = createTRPCRouter({
}), }),
); );
await dockerCache.invalidateAsync(); const innerHandler = dockerContainersRequestHandler.handler({});
await innerHandler.invalidateAsync();
}), }),
}); });
@@ -180,20 +142,6 @@ interface DockerContainer {
image: string; image: string;
ports: Port[]; ports: Port[];
iconUrl: string | null; iconUrl: string | null;
} cpuUsage: number;
memoryUsage: number;
function sanitizeContainers(
containers: (ContainerInfo & { instance: string; iconUrl: string | null })[],
): DockerContainer[] {
return containers.map((container) => {
return {
name: container.Names[0]?.split("/")[1] ?? "Unknown",
id: container.Id,
instance: container.instance,
state: container.State as ContainerState,
image: container.Image,
ports: container.Ports,
iconUrl: container.iconUrl,
};
});
} }
@@ -4,14 +4,26 @@ import { describe, expect, test, vi } from "vitest";
import type { Session } from "@homarr/auth"; import type { Session } from "@homarr/auth";
import { objectKeys } from "@homarr/common"; import { objectKeys } from "@homarr/common";
import type { Database } from "@homarr/db"; import type { Database } from "@homarr/db";
import { getPermissionsWithChildren } from "@homarr/definitions";
import type { GroupPermissionKey } from "@homarr/definitions"; import type { GroupPermissionKey } from "@homarr/definitions";
import { getPermissionsWithChildren } from "@homarr/definitions";
import type { RouterInputs } from "../../.."; import type { RouterInputs } from "../../..";
import { dockerRouter } from "../../docker/docker-router"; import { dockerRouter } from "../../docker/docker-router";
// Mock the auth module to return an empty session // Mock the auth module to return an empty session
vi.mock("@homarr/auth", () => ({ auth: () => ({}) as Session })); vi.mock("@homarr/auth", () => ({ auth: () => ({}) as Session }));
vi.mock("@homarr/request-handler/docker", () => ({
dockerContainersRequestHandler: {
handler: () => ({
getCachedOrUpdatedDataAsync: async () => {
return await Promise.resolve({ containers: [] });
},
invalidateAsync: async () => {
return await Promise.resolve();
},
}),
},
}));
vi.mock("@homarr/redis", () => ({ vi.mock("@homarr/redis", () => ({
createCacheChannel: () => ({ createCacheChannel: () => ({
// eslint-disable-next-line @typescript-eslint/require-await // eslint-disable-next-line @typescript-eslint/require-await
@@ -22,6 +34,7 @@ vi.mock("@homarr/redis", () => ({
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
invalidateAsync: async () => {}, invalidateAsync: async () => {},
}), }),
createWidgetOptionsChannel: () => ({}),
})); }));
vi.mock("@homarr/docker/env", () => ({ vi.mock("@homarr/docker/env", () => ({
@@ -46,6 +59,7 @@ const validInputs: {
[key in (typeof procedureKeys)[number]]: RouterInputs["docker"][key]; [key in (typeof procedureKeys)[number]]: RouterInputs["docker"][key];
} = { } = {
getContainers: undefined, getContainers: undefined,
subscribeContainers: undefined,
startAll: { ids: ["1"] }, startAll: { ids: ["1"] },
stopAll: { ids: ["1"] }, stopAll: { ids: ["1"] },
restartAll: { ids: ["1"] }, restartAll: { ids: ["1"] },
+8 -4
View File
@@ -19,10 +19,11 @@ const createDownloadClientIntegrationMiddleware = (action: IntegrationAction) =>
export const downloadsRouter = createTRPCRouter({ export const downloadsRouter = createTRPCRouter({
getJobsAndStatuses: publicProcedure getJobsAndStatuses: publicProcedure
.concat(createDownloadClientIntegrationMiddleware("query")) .concat(createDownloadClientIntegrationMiddleware("query"))
.query(async ({ ctx }) => { .input(z.object({ limitPerIntegration: z.number().default(50) }))
.query(async ({ ctx, input }) => {
return await Promise.all( return await Promise.all(
ctx.integrations.map(async (integration) => { ctx.integrations.map(async (integration) => {
const innerHandler = downloadClientRequestHandler.handler(integration, {}); const innerHandler = downloadClientRequestHandler.handler(integration, { limit: input.limitPerIntegration });
const { data, timestamp } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false }); const { data, timestamp } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false });
@@ -40,7 +41,8 @@ export const downloadsRouter = createTRPCRouter({
}), }),
subscribeToJobsAndStatuses: publicProcedure subscribeToJobsAndStatuses: publicProcedure
.concat(createDownloadClientIntegrationMiddleware("query")) .concat(createDownloadClientIntegrationMiddleware("query"))
.subscription(({ ctx }) => { .input(z.object({ limitPerIntegration: z.number().default(50) }))
.subscription(({ ctx, input }) => {
return observable<{ return observable<{
integration: Modify<Integration, { kind: IntegrationKindByCategory<"downloadClient"> }>; integration: Modify<Integration, { kind: IntegrationKindByCategory<"downloadClient"> }>;
data: DownloadClientJobsAndStatus; data: DownloadClientJobsAndStatus;
@@ -48,7 +50,9 @@ export const downloadsRouter = createTRPCRouter({
const unsubscribes: (() => void)[] = []; const unsubscribes: (() => void)[] = [];
for (const integrationWithSecrets of ctx.integrations) { for (const integrationWithSecrets of ctx.integrations) {
const { decryptedSecrets: _, ...integration } = integrationWithSecrets; const { decryptedSecrets: _, ...integration } = integrationWithSecrets;
const innerHandler = downloadClientRequestHandler.handler(integrationWithSecrets, {}); const innerHandler = downloadClientRequestHandler.handler(integrationWithSecrets, {
limit: input.limitPerIntegration,
});
const unsubscribe = innerHandler.subscribe((data) => { const unsubscribe = innerHandler.subscribe((data) => {
emit.next({ emit.next({
integration, integration,
+20 -36
View File
@@ -1,40 +1,24 @@
import { lazy } from "@trpc/server";
import { createTRPCRouter } from "../../trpc"; import { createTRPCRouter } from "../../trpc";
import { appRouter } from "./app";
import { calendarRouter } from "./calendar";
import { dnsHoleRouter } from "./dns-hole";
import { downloadsRouter } from "./downloads";
import { healthMonitoringRouter } from "./health-monitoring";
import { indexerManagerRouter } from "./indexer-manager";
import { mediaRequestsRouter } from "./media-requests";
import { mediaServerRouter } from "./media-server";
import { mediaTranscodingRouter } from "./media-transcoding";
import { minecraftRouter } from "./minecraft";
import { networkControllerRouter } from "./network-controller";
import { notebookRouter } from "./notebook";
import { optionsRouter } from "./options";
import { releasesRouter } from "./releases";
import { rssFeedRouter } from "./rssFeed";
import { smartHomeRouter } from "./smart-home";
import { stockPriceRouter } from "./stocks";
import { weatherRouter } from "./weather";
export const widgetRouter = createTRPCRouter({ export const widgetRouter = createTRPCRouter({
notebook: notebookRouter, notebook: lazy(() => import("./notebook").then((mod) => mod.notebookRouter)),
weather: weatherRouter, weather: lazy(() => import("./weather").then((mod) => mod.weatherRouter)),
app: appRouter, app: lazy(() => import("./app").then((mod) => mod.appRouter)),
dnsHole: dnsHoleRouter, dnsHole: lazy(() => import("./dns-hole").then((mod) => mod.dnsHoleRouter)),
smartHome: smartHomeRouter, smartHome: lazy(() => import("./smart-home").then((mod) => mod.smartHomeRouter)),
stockPrice: stockPriceRouter, stockPrice: lazy(() => import("./stocks").then((mod) => mod.stockPriceRouter)),
mediaServer: mediaServerRouter, mediaServer: lazy(() => import("./media-server").then((mod) => mod.mediaServerRouter)),
calendar: calendarRouter, calendar: lazy(() => import("./calendar").then((mod) => mod.calendarRouter)),
downloads: downloadsRouter, downloads: lazy(() => import("./downloads").then((mod) => mod.downloadsRouter)),
mediaRequests: mediaRequestsRouter, mediaRequests: lazy(() => import("./media-requests").then((mod) => mod.mediaRequestsRouter)),
rssFeed: rssFeedRouter, rssFeed: lazy(() => import("./rssFeed").then((mod) => mod.rssFeedRouter)),
indexerManager: indexerManagerRouter, indexerManager: lazy(() => import("./indexer-manager").then((mod) => mod.indexerManagerRouter)),
healthMonitoring: healthMonitoringRouter, healthMonitoring: lazy(() => import("./health-monitoring").then((mod) => mod.healthMonitoringRouter)),
mediaTranscoding: mediaTranscodingRouter, mediaTranscoding: lazy(() => import("./media-transcoding").then((mod) => mod.mediaTranscodingRouter)),
minecraft: minecraftRouter, minecraft: lazy(() => import("./minecraft").then((mod) => mod.minecraftRouter)),
options: optionsRouter, options: lazy(() => import("./options").then((mod) => mod.optionsRouter)),
releases: releasesRouter, releases: lazy(() => import("./releases").then((mod) => mod.releasesRouter)),
networkController: networkControllerRouter, networkController: lazy(() => import("./network-controller").then((mod) => mod.networkControllerRouter)),
}); });
+2 -2
View File
@@ -39,7 +39,7 @@
"next-auth": "5.0.0-beta.28", "next-auth": "5.0.0-beta.28",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"zod": "^3.24.4" "zod": "^3.25.30"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
@@ -47,7 +47,7 @@
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/bcrypt": "5.0.2", "@types/bcrypt": "5.0.2",
"@types/cookies": "0.9.0", "@types/cookies": "0.9.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
@@ -23,21 +23,22 @@ export type BoardPermissionsProps = (
export const constructBoardPermissions = (board: BoardPermissionsProps, session: Session | null) => { export const constructBoardPermissions = (board: BoardPermissionsProps, session: Session | null) => {
const creatorId = "creator" in board ? board.creator?.id : board.creatorId; const creatorId = "creator" in board ? board.creator?.id : board.creatorId;
const isCreator = session !== null && session.user.id === creatorId;
return { return {
hasFullAccess: hasFullAccess:
session?.user.id === creatorId || isCreator ||
board.userPermissions.some(({ permission }) => permission === "full") || board.userPermissions.some(({ permission }) => permission === "full") ||
board.groupPermissions.some(({ permission }) => permission === "full") || board.groupPermissions.some(({ permission }) => permission === "full") ||
(session?.user.permissions.includes("board-full-all") ?? false), (session?.user.permissions.includes("board-full-all") ?? false),
hasChangeAccess: hasChangeAccess:
session?.user.id === creatorId || isCreator ||
board.userPermissions.some(({ permission }) => permission === "modify" || permission === "full") || board.userPermissions.some(({ permission }) => permission === "modify" || permission === "full") ||
board.groupPermissions.some(({ permission }) => permission === "modify" || permission === "full") || board.groupPermissions.some(({ permission }) => permission === "modify" || permission === "full") ||
(session?.user.permissions.includes("board-modify-all") ?? false) || (session?.user.permissions.includes("board-modify-all") ?? false) ||
(session?.user.permissions.includes("board-full-all") ?? false), (session?.user.permissions.includes("board-full-all") ?? false),
hasViewAccess: hasViewAccess:
session?.user.id === creatorId || isCreator ||
board.userPermissions.length >= 1 || board.userPermissions.length >= 1 ||
board.groupPermissions.length >= 1 || board.groupPermissions.length >= 1 ||
board.isPublic || board.isPublic ||
@@ -286,4 +286,22 @@ describe("constructBoardPermissions", () => {
expect(result.hasChangeAccess).toBe(false); expect(result.hasChangeAccess).toBe(false);
expect(result.hasViewAccess).toBe(true); expect(result.hasViewAccess).toBe(true);
}); });
test("should return all false when creator is null and session is null", () => {
// Arrange
const board = {
creator: null,
userPermissions: [],
groupPermissions: [],
isPublic: false,
};
const session = null;
// Act
const result = constructBoardPermissions(board, session);
// Assert
expect(result.hasFullAccess).toBe(false);
expect(result.hasChangeAccess).toBe(false);
expect(result.hasViewAccess).toBe(false);
});
}); });
+1 -1
View File
@@ -32,7 +32,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+2 -2
View File
@@ -24,13 +24,13 @@
"dependencies": { "dependencies": {
"@homarr/common": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0",
"@homarr/db": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0",
"undici": "7.9.0" "undici": "7.10.0"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+2 -1
View File
@@ -34,7 +34,8 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "esbuild": "^0.25.5",
"eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+4 -4
View File
@@ -33,15 +33,15 @@
"next": "15.3.2", "next": "15.3.2",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"undici": "7.9.0", "undici": "7.10.0",
"zod": "^3.24.4", "zod": "^3.25.30",
"zod-validation-error": "^3.4.0" "zod-validation-error": "^3.4.1"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+1 -1
View File
@@ -24,7 +24,7 @@ export class LoggingAgent extends Agent {
url.searchParams.set(key, "REDACTED"); url.searchParams.set(key, "REDACTED");
}); });
logger.info( logger.debug(
`Dispatching request ${url.toString().replaceAll("=&", "&")} (${Object.keys(options.headers ?? {}).length} headers)`, `Dispatching request ${url.toString().replaceAll("=&", "&")} (${Object.keys(options.headers ?? {}).length} headers)`,
); );
return super.dispatch(options, handler); return super.dispatch(options, handler);
+4 -4
View File
@@ -21,7 +21,7 @@ const REDACTED = "REDACTED";
describe("LoggingAgent should log all requests", () => { describe("LoggingAgent should log all requests", () => {
test("should log all requests", () => { test("should log all requests", () => {
// Arrange // Arrange
const infoLogSpy = vi.spyOn(logger, "info"); const infoLogSpy = vi.spyOn(logger, "debug");
const agent = new LoggingAgent(); const agent = new LoggingAgent();
// Act // Act
@@ -33,7 +33,7 @@ describe("LoggingAgent should log all requests", () => {
test("should show amount of headers", () => { test("should show amount of headers", () => {
// Arrange // Arrange
const infoLogSpy = vi.spyOn(logger, "info"); const infoLogSpy = vi.spyOn(logger, "debug");
const agent = new LoggingAgent(); const agent = new LoggingAgent();
// Act // Act
@@ -68,7 +68,7 @@ describe("LoggingAgent should log all requests", () => {
[`/?stringWith13Chars=${"a".repeat(13)}`, `/?stringWith13Chars=${REDACTED}`], [`/?stringWith13Chars=${"a".repeat(13)}`, `/?stringWith13Chars=${REDACTED}`],
])("should redact sensitive data in url https://homarr.dev%s", (path, expected) => { ])("should redact sensitive data in url https://homarr.dev%s", (path, expected) => {
// Arrange // Arrange
const infoLogSpy = vi.spyOn(logger, "info"); const infoLogSpy = vi.spyOn(logger, "debug");
const agent = new LoggingAgent(); const agent = new LoggingAgent();
// Act // Act
@@ -87,7 +87,7 @@ describe("LoggingAgent should log all requests", () => {
["date times", "/?datetime=2022-01-01T00:00:00.000Z"], ["date times", "/?datetime=2022-01-01T00:00:00.000Z"],
])("should not redact values that are %s", (_reason, path) => { ])("should not redact values that are %s", (_reason, path) => {
// Arrange // Arrange
const infoLogSpy = vi.spyOn(logger, "info"); const infoLogSpy = vi.spyOn(logger, "debug");
const agent = new LoggingAgent(); const agent = new LoggingAgent();
// Act // Act
+1 -1
View File
@@ -33,7 +33,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+1
View File
@@ -24,6 +24,7 @@ export const cronJobs = {
mediaTranscoding: { preventManualExecution: false }, mediaTranscoding: { preventManualExecution: false },
minecraftServerStatus: { preventManualExecution: false }, minecraftServerStatus: { preventManualExecution: false },
networkController: { preventManualExecution: false }, networkController: { preventManualExecution: false },
dockerContainers: { preventManualExecution: false },
} satisfies Record<JobGroupKeys, { preventManualExecution?: boolean }>; } satisfies Record<JobGroupKeys, { preventManualExecution?: boolean }>;
/** /**
+1 -1
View File
@@ -7,6 +7,6 @@ import { cronJobRunnerChannel } from ".";
*/ */
export const registerCronJobRunner = () => { export const registerCronJobRunner = () => {
cronJobRunnerChannel.subscribe((jobName) => { cronJobRunnerChannel.subscribe((jobName) => {
jobGroup.runManually(jobName); void jobGroup.runManuallyAsync(jobName);
}); });
}; };
+1 -1
View File
@@ -29,7 +29,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+2 -2
View File
@@ -25,14 +25,14 @@
"prettier": "@homarr/prettier-config", "prettier": "@homarr/prettier-config",
"dependencies": { "dependencies": {
"@homarr/common": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0",
"node-cron": "^3.0.3" "node-cron": "^4.0.7"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/node-cron": "^3.0.11", "@types/node-cron": "^3.0.11",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+7 -7
View File
@@ -1,5 +1,6 @@
import { AxiosError } from "axios"; import { AxiosError } from "axios";
import cron from "node-cron"; import type { ScheduledTask } from "node-cron";
import { schedule, validate } from "node-cron";
import { Stopwatch } from "@homarr/common"; import { Stopwatch } from "@homarr/common";
import type { MaybePromise } from "@homarr/common/types"; import type { MaybePromise } from "@homarr/common/types";
@@ -27,7 +28,7 @@ const createCallback = <TAllowedNames extends string, TName extends TAllowedName
options: CreateCronJobOptions, options: CreateCronJobOptions,
creatorOptions: CreateCronJobCreatorOptions<TAllowedNames>, creatorOptions: CreateCronJobCreatorOptions<TAllowedNames>,
) => { ) => {
const expectedMaximumDurationInMillis = options.expectedMaximumDurationInMillis ?? 1000; const expectedMaximumDurationInMillis = options.expectedMaximumDurationInMillis ?? 2500;
return (callback: () => MaybePromise<void>) => { return (callback: () => MaybePromise<void>) => {
const catchingCallbackAsync = async () => { const catchingCallbackAsync = async () => {
try { try {
@@ -64,12 +65,11 @@ const createCallback = <TAllowedNames extends string, TName extends TAllowedName
/** /**
* We are not using the runOnInit method as we want to run the job only once we start the cron job schedule manually. * We are not using the runOnInit method as we want to run the job only once we start the cron job schedule manually.
* This allows us to always run it once we start it. Additionally it will not run the callback if only the cron job file is imported. * This allows us to always run it once we start it. Additionally, it will not run the callback if only the cron job file is imported.
*/ */
let scheduledTask: cron.ScheduledTask | null = null; let scheduledTask: ScheduledTask | null = null;
if (cronExpression !== "never") { if (cronExpression !== "never") {
scheduledTask = cron.schedule(cronExpression, () => void catchingCallbackAsync(), { scheduledTask = schedule(cronExpression, () => void catchingCallbackAsync(), {
scheduled: false,
name, name,
timezone: creatorOptions.timezone, timezone: creatorOptions.timezone,
}); });
@@ -110,7 +110,7 @@ export const createCronJobCreator = <TAllowedNames extends string = string>(
options: CreateCronJobOptions = { runOnStart: false }, options: CreateCronJobOptions = { runOnStart: false },
) => { ) => {
creatorOptions.logger.logDebug(`Validating cron expression '${cronExpression}' for job: ${name}`); creatorOptions.logger.logDebug(`Validating cron expression '${cronExpression}' for job: ${name}`);
if (cronExpression !== "never" && !cron.validate(cronExpression)) { if (cronExpression !== "never" && !validate(cronExpression)) {
throw new Error(`Invalid cron expression '${cronExpression}' for job '${name}'`); throw new Error(`Invalid cron expression '${cronExpression}' for job '${name}'`);
} }
creatorOptions.logger.logDebug(`Cron job expression '${cronExpression}' for job ${name} is valid`); creatorOptions.logger.logDebug(`Cron job expression '${cronExpression}' for job ${name} is valid`);
+8 -8
View File
@@ -34,33 +34,33 @@ export const createJobGroupCreator = <TAllowedNames extends string = string>(
options.logger.logInfo(`Starting schedule cron job ${job.name}.`); options.logger.logInfo(`Starting schedule cron job ${job.name}.`);
await job.onStartAsync(); await job.onStartAsync();
job.scheduledTask?.start(); await job.scheduledTask?.start();
}, },
startAllAsync: async () => { startAllAsync: async () => {
for (const job of jobRegistry.values()) { for (const job of jobRegistry.values()) {
options.logger.logInfo(`Starting schedule of cron job ${job.name}.`); options.logger.logInfo(`Starting schedule of cron job ${job.name}.`);
await job.onStartAsync(); await job.onStartAsync();
job.scheduledTask?.start(); await job.scheduledTask?.start();
} }
}, },
runManually: (name: keyof TJobs) => { runManuallyAsync: async (name: keyof TJobs) => {
const job = jobRegistry.get(name as string); const job = jobRegistry.get(name as string);
if (!job) return; if (!job) return;
options.logger.logInfo(`Running schedule cron job ${job.name} manually.`); options.logger.logInfo(`Running schedule cron job ${job.name} manually.`);
job.scheduledTask?.now(); await job.scheduledTask?.execute();
}, },
stop: (name: keyof TJobs) => { stopAsync: async (name: keyof TJobs) => {
const job = jobRegistry.get(name as string); const job = jobRegistry.get(name as string);
if (!job) return; if (!job) return;
options.logger.logInfo(`Stopping schedule cron job ${job.name}.`); options.logger.logInfo(`Stopping schedule cron job ${job.name}.`);
job.scheduledTask?.stop(); await job.scheduledTask?.stop();
}, },
stopAll: () => { stopAllAsync: async () => {
for (const job of jobRegistry.values()) { for (const job of jobRegistry.values()) {
options.logger.logInfo(`Stopping schedule cron job ${job.name}.`); options.logger.logInfo(`Stopping schedule cron job ${job.name}.`);
job.scheduledTask?.stop(); await job.scheduledTask?.stop();
} }
}, },
getJobRegistry() { getJobRegistry() {
+1 -1
View File
@@ -44,7 +44,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+2
View File
@@ -1,4 +1,5 @@
import { analyticsJob } from "./jobs/analytics"; import { analyticsJob } from "./jobs/analytics";
import { dockerContainersJob } from "./jobs/docker";
import { iconsUpdaterJob } from "./jobs/icons-updater"; import { iconsUpdaterJob } from "./jobs/icons-updater";
import { dnsHoleJob } from "./jobs/integrations/dns-hole"; import { dnsHoleJob } from "./jobs/integrations/dns-hole";
import { downloadsJob } from "./jobs/integrations/downloads"; import { downloadsJob } from "./jobs/integrations/downloads";
@@ -35,6 +36,7 @@ export const jobGroup = createCronJobGroup({
updateChecker: updateCheckerJob, updateChecker: updateCheckerJob,
mediaTranscoding: mediaTranscodingJob, mediaTranscoding: mediaTranscodingJob,
minecraftServerStatus: minecraftServerStatusJob, minecraftServerStatus: minecraftServerStatusJob,
dockerContainers: dockerContainersJob,
networkController: networkControllerJob, networkController: networkControllerJob,
}); });
+28
View File
@@ -0,0 +1,28 @@
import SuperJSON from "superjson";
import { EVERY_MINUTE } from "@homarr/cron-jobs-core/expressions";
import { db, eq } from "@homarr/db";
import { items } from "@homarr/db/schema";
import { logger } from "@homarr/log";
import { dockerContainersRequestHandler } from "@homarr/request-handler/docker";
import type { WidgetComponentProps } from "../../../widgets";
import { createCronJob } from "../lib";
export const dockerContainersJob = createCronJob("dockerContainers", EVERY_MINUTE).withCallback(async () => {
const dockerItems = await db.query.items.findMany({
where: eq(items.kind, "dockerContainers"),
});
await Promise.allSettled(
dockerItems.map(async (item) => {
try {
const options = SuperJSON.parse<WidgetComponentProps<"dockerContainers">["options"]>(item.options);
const innerHandler = dockerContainersRequestHandler.handler(options);
await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: true });
} catch (error) {
logger.error("Failed to update Docker container status", { item, error });
}
}),
);
});
@@ -8,7 +8,9 @@ export const downloadsJob = createCronJob("downloads", EVERY_5_SECONDS).withCall
createRequestIntegrationJobHandler(downloadClientRequestHandler.handler, { createRequestIntegrationJobHandler(downloadClientRequestHandler.handler, {
widgetKinds: ["downloads"], widgetKinds: ["downloads"],
getInput: { getInput: {
downloads: () => ({}), downloads: (options) => ({
limit: options.limitPerIntegration,
}),
}, },
}), }),
); );
+4 -3
View File
@@ -44,9 +44,9 @@
"@homarr/env": "workspace:^0.1.0", "@homarr/env": "workspace:^0.1.0",
"@homarr/log": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0",
"@homarr/server-settings": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0",
"@mantine/core": "^8.0.1", "@mantine/core": "^8.0.2",
"@paralleldrive/cuid2": "^2.2.2", "@paralleldrive/cuid2": "^2.2.2",
"@testcontainers/mysql": "^10.26.0", "@testcontainers/mysql": "^10.28.0",
"better-sqlite3": "^11.10.0", "better-sqlite3": "^11.10.0",
"dotenv": "^16.5.0", "dotenv": "^16.5.0",
"drizzle-kit": "^0.31.1", "drizzle-kit": "^0.31.1",
@@ -60,7 +60,8 @@
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/better-sqlite3": "7.6.13", "@types/better-sqlite3": "7.6.13",
"dotenv-cli": "^8.0.0", "dotenv-cli": "^8.0.0",
"eslint": "^9.26.0", "esbuild": "^0.25.5",
"eslint": "^9.27.0",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"tsx": "4.19.4", "tsx": "4.19.4",
"typescript": "^5.8.3" "typescript": "^5.8.3"
+2 -2
View File
@@ -25,13 +25,13 @@
"dependencies": { "dependencies": {
"@homarr/common": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0",
"fast-xml-parser": "^5.2.3", "fast-xml-parser": "^5.2.3",
"zod": "^3.24.4" "zod": "^3.25.30"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"tsx": "4.19.4", "tsx": "4.19.4",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
+1
View File
@@ -24,5 +24,6 @@ export const widgetKinds = [
"indexerManager", "indexerManager",
"healthMonitoring", "healthMonitoring",
"releases", "releases",
"dockerContainers",
] as const; ] as const;
export type WidgetKind = (typeof widgetKinds)[number]; export type WidgetKind = (typeof widgetKinds)[number];
+3 -2
View File
@@ -6,6 +6,7 @@
"type": "module", "type": "module",
"exports": { "exports": {
".": "./index.ts", ".": "./index.ts",
"./shared": "./src/shared.ts",
"./env": "./src/env.ts" "./env": "./src/env.ts"
}, },
"typesVersions": { "typesVersions": {
@@ -31,8 +32,8 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/dockerode": "^3.3.38", "@types/dockerode": "^3.3.39",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+13
View File
@@ -0,0 +1,13 @@
import type { MantineColor } from "@mantine/core";
import type { ContainerState } from ".";
export const containerStateColorMap = {
created: "cyan",
running: "green",
paused: "yellow",
restarting: "orange",
exited: "red",
removing: "pink",
dead: "dark",
} satisfies Record<ContainerState, MantineColor>;
+3 -3
View File
@@ -23,14 +23,14 @@
}, },
"prettier": "@homarr/prettier-config", "prettier": "@homarr/prettier-config",
"dependencies": { "dependencies": {
"@t3-oss/env-nextjs": "^0.13.4", "@t3-oss/env-nextjs": "^0.13.6",
"zod": "^3.24.4" "zod": "^3.25.30"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+3 -3
View File
@@ -26,14 +26,14 @@
"@homarr/common": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0",
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@mantine/form": "^8.0.1", "@mantine/form": "^8.0.2",
"zod": "^3.24.4" "zod": "^3.25.30"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+3 -3
View File
@@ -29,15 +29,15 @@
"@homarr/notifications": "workspace:^0.1.0", "@homarr/notifications": "workspace:^0.1.0",
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@mantine/core": "^8.0.1", "@mantine/core": "^8.0.2",
"react": "19.1.0", "react": "19.1.0",
"zod": "^3.24.4" "zod": "^3.25.30"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+1 -1
View File
@@ -31,7 +31,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+3 -3
View File
@@ -42,9 +42,9 @@
"node-ical": "^0.20.1", "node-ical": "^0.20.1",
"proxmox-api": "1.1.1", "proxmox-api": "1.1.1",
"tsdav": "^2.1.4", "tsdav": "^2.1.4",
"undici": "7.9.0", "undici": "7.10.0",
"xml2js": "^0.6.2", "xml2js": "^0.6.2",
"zod": "^3.24.4" "zod": "^3.25.30"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
@@ -52,7 +52,7 @@
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/node-unifi": "^2.5.1", "@types/node-unifi": "^2.5.1",
"@types/xml2js": "^0.4.14", "@types/xml2js": "^0.4.14",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
@@ -12,7 +12,7 @@ import type { DownloadClientItem } from "../../interfaces/downloads/download-cli
import type { Aria2Download, Aria2GetClient } from "./aria2-types"; import type { Aria2Download, Aria2GetClient } from "./aria2-types";
export class Aria2Integration extends DownloadClientIntegration { export class Aria2Integration extends DownloadClientIntegration {
public async getClientJobsAndStatusAsync(): Promise<DownloadClientJobsAndStatus> { public async getClientJobsAndStatusAsync(input: { limit: number }): Promise<DownloadClientJobsAndStatus> {
const client = this.getClient(); const client = this.getClient();
const keys: (keyof Aria2Download)[] = [ const keys: (keyof Aria2Download)[] = [
"bittorrent", "bittorrent",
@@ -27,12 +27,12 @@ export class Aria2Integration extends DownloadClientIntegration {
]; ];
const [activeDownloads, waitingDownloads, stoppedDownloads, globalStats] = await Promise.all([ const [activeDownloads, waitingDownloads, stoppedDownloads, globalStats] = await Promise.all([
client.tellActive(), client.tellActive(),
client.tellWaiting(0, 1000, keys), client.tellWaiting(0, input.limit, keys),
client.tellStopped(0, 1000, keys), client.tellStopped(0, input.limit, keys),
client.getGlobalStat(), client.getGlobalStat(),
]); ]);
const downloads = [...activeDownloads, ...waitingDownloads, ...stoppedDownloads]; const downloads = [...activeDownloads, ...waitingDownloads, ...stoppedDownloads].slice(0, input.limit);
const allPaused = downloads.every((download) => download.status === "paused"); const allPaused = downloads.every((download) => download.status === "paused");
return { return {
@@ -29,9 +29,10 @@ export class DelugeIntegration extends DownloadClientIntegration {
}; };
} }
public async getClientJobsAndStatusAsync(): Promise<DownloadClientJobsAndStatus> { public async getClientJobsAndStatusAsync(input: { limit: number }): Promise<DownloadClientJobsAndStatus> {
const type = "torrent"; const type = "torrent";
const client = await this.getClientAsync(); const client = await this.getClientAsync();
// Currently there is no way to limit the number of returned torrents
const { const {
stats: { download_rate, upload_rate }, stats: { download_rate, upload_rate },
torrents: rawTorrents, torrents: rawTorrents,
@@ -49,27 +50,29 @@ export class DelugeIntegration extends DownloadClientIntegration {
}, },
types: [type], types: [type],
}; };
const items = torrents.map((torrent): DownloadClientItem => { const items = torrents
const state = DelugeIntegration.getTorrentState(torrent.state); .map((torrent): DownloadClientItem => {
return { const state = DelugeIntegration.getTorrentState(torrent.state);
type, return {
id: torrent.id, type,
index: torrent.queue, id: torrent.id,
name: torrent.name, index: torrent.queue,
size: torrent.total_wanted, name: torrent.name,
sent: torrent.total_uploaded, size: torrent.total_wanted,
downSpeed: torrent.progress !== 100 ? torrent.download_payload_rate : undefined, sent: torrent.total_uploaded,
upSpeed: torrent.upload_payload_rate, downSpeed: torrent.progress !== 100 ? torrent.download_payload_rate : undefined,
time: upSpeed: torrent.upload_payload_rate,
torrent.progress === 100 time:
? Math.min((torrent.completed_time - dayjs().unix()) * 1000, -1) torrent.progress === 100
: Math.max(torrent.eta * 1000, 0), ? Math.min((torrent.completed_time - dayjs().unix()) * 1000, -1)
added: torrent.time_added * 1000, : Math.max(torrent.eta * 1000, 0),
state, added: torrent.time_added * 1000,
progress: torrent.progress / 100, state,
category: torrent.label, progress: torrent.progress / 100,
}; category: torrent.label,
}); };
})
.slice(0, input.limit);
return { status, items }; return { status, items };
} }
@@ -20,7 +20,7 @@ export class NzbGetIntegration extends DownloadClientIntegration {
}; };
} }
public async getClientJobsAndStatusAsync(): Promise<DownloadClientJobsAndStatus> { public async getClientJobsAndStatusAsync(input: { limit: number }): Promise<DownloadClientJobsAndStatus> {
const type = "usenet"; const type = "usenet";
const queue = await this.nzbGetApiCallAsync("listgroups"); const queue = await this.nzbGetApiCallAsync("listgroups");
const history = await this.nzbGetApiCallAsync("history"); const history = await this.nzbGetApiCallAsync("history");
@@ -65,7 +65,8 @@ export class NzbGetIntegration extends DownloadClientIntegration {
category: file.Category, category: file.Category,
}; };
}), }),
); )
.slice(0, input.limit);
return { status, items }; return { status, items };
} }
@@ -26,10 +26,10 @@ export class QBitTorrentIntegration extends DownloadClientIntegration {
}; };
} }
public async getClientJobsAndStatusAsync(): Promise<DownloadClientJobsAndStatus> { public async getClientJobsAndStatusAsync(input: { limit: number }): Promise<DownloadClientJobsAndStatus> {
const type = "torrent"; const type = "torrent";
const client = await this.getClientAsync(); const client = await this.getClientAsync();
const torrents = await client.listTorrents(); const torrents = await client.listTorrents({ limit: input.limit });
const rates = torrents.reduce( const rates = torrents.reduce(
({ down, up }, { dlspeed, upspeed }) => ({ down: down + dlspeed, up: up + upspeed }), ({ down, up }, { dlspeed, upspeed }) => ({ down: down + dlspeed, up: up + upspeed }),
{ down: 0, up: 0 }, { down: 0, up: 0 },
@@ -22,10 +22,14 @@ export class SabnzbdIntegration extends DownloadClientIntegration {
return { success: true }; return { success: true };
} }
public async getClientJobsAndStatusAsync(): Promise<DownloadClientJobsAndStatus> { public async getClientJobsAndStatusAsync(input: { limit: number }): Promise<DownloadClientJobsAndStatus> {
const type = "usenet"; const type = "usenet";
const { queue } = await queueSchema.parseAsync(await this.sabNzbApiCallAsync("queue")); const { queue } = await queueSchema.parseAsync(
const { history } = await historySchema.parseAsync(await this.sabNzbApiCallAsync("history")); await this.sabNzbApiCallAsync("queue", { limit: input.limit.toString() }),
);
const { history } = await historySchema.parseAsync(
await this.sabNzbApiCallAsync("history", { limit: input.limit.toString() }),
);
const status: DownloadClientStatus = { const status: DownloadClientStatus = {
paused: queue.paused, paused: queue.paused,
rates: { down: Math.floor(Number(queue.kbpersec) * 1024) }, //Actually rounded kiBps () rates: { down: Math.floor(Number(queue.kbpersec) * 1024) }, //Actually rounded kiBps ()
@@ -73,7 +77,8 @@ export class SabnzbdIntegration extends DownloadClientIntegration {
category: slot.category, category: slot.category,
}; };
}), }),
); )
.slice(0, input.limit);
return { status, items }; return { status, items };
} }
@@ -23,9 +23,10 @@ export class TransmissionIntegration extends DownloadClientIntegration {
}; };
} }
public async getClientJobsAndStatusAsync(): Promise<DownloadClientJobsAndStatus> { public async getClientJobsAndStatusAsync(input: { limit: number }): Promise<DownloadClientJobsAndStatus> {
const type = "torrent"; const type = "torrent";
const client = await this.getClientAsync(); const client = await this.getClientAsync();
// Currently there is no way to limit the number of returned torrents
const { torrents } = (await client.listTorrents()).arguments; const { torrents } = (await client.listTorrents()).arguments;
const rates = torrents.reduce( const rates = torrents.reduce(
({ down, up }, { rateDownload, rateUpload }) => ({ down: down + rateDownload, up: up + rateUpload }), ({ down, up }, { rateDownload, rateUpload }) => ({ down: down + rateDownload, up: up + rateUpload }),
@@ -34,27 +35,29 @@ export class TransmissionIntegration extends DownloadClientIntegration {
const paused = const paused =
torrents.find(({ status }) => TransmissionIntegration.getTorrentState(status) !== "paused") === undefined; torrents.find(({ status }) => TransmissionIntegration.getTorrentState(status) !== "paused") === undefined;
const status: DownloadClientStatus = { paused, rates, types: [type] }; const status: DownloadClientStatus = { paused, rates, types: [type] };
const items = torrents.map((torrent): DownloadClientItem => { const items = torrents
const state = TransmissionIntegration.getTorrentState(torrent.status); .map((torrent): DownloadClientItem => {
return { const state = TransmissionIntegration.getTorrentState(torrent.status);
type, return {
id: torrent.hashString, type,
index: torrent.queuePosition, id: torrent.hashString,
name: torrent.name, index: torrent.queuePosition,
size: torrent.totalSize, name: torrent.name,
sent: torrent.uploadedEver, size: torrent.totalSize,
downSpeed: torrent.percentDone !== 1 ? torrent.rateDownload : undefined, sent: torrent.uploadedEver,
upSpeed: torrent.rateUpload, downSpeed: torrent.percentDone !== 1 ? torrent.rateDownload : undefined,
time: upSpeed: torrent.rateUpload,
torrent.percentDone === 1 time:
? Math.min(torrent.doneDate * 1000 - dayjs().valueOf(), -1) torrent.percentDone === 1
: Math.max(torrent.eta * 1000, 0), ? Math.min(torrent.doneDate * 1000 - dayjs().valueOf(), -1)
added: torrent.addedDate * 1000, : Math.max(torrent.eta * 1000, 0),
state, added: torrent.addedDate * 1000,
progress: torrent.percentDone, state,
category: torrent.labels, progress: torrent.percentDone,
}; category: torrent.labels,
}); };
})
.slice(0, input.limit);
return { status, items }; return { status, items };
} }
@@ -4,7 +4,7 @@ import type { DownloadClientItem } from "./download-client-items";
export abstract class DownloadClientIntegration extends Integration { export abstract class DownloadClientIntegration extends Integration {
/** Get download client's status and list of all of it's items */ /** Get download client's status and list of all of it's items */
public abstract getClientJobsAndStatusAsync(): Promise<DownloadClientJobsAndStatus>; public abstract getClientJobsAndStatusAsync(input: { limit: number }): Promise<DownloadClientJobsAndStatus>;
/** Pauses the client or all of it's items */ /** Pauses the client or all of it's items */
public abstract pauseQueueAsync(): Promise<void>; public abstract pauseQueueAsync(): Promise<void>;
/** Pause a single item using it's ID */ /** Pause a single item using it's ID */
+5 -5
View File
@@ -46,7 +46,7 @@ describe("Aria2 integration", () => {
// Acts // Acts
const actAsync = async () => await aria2Integration.pauseQueueAsync(); const actAsync = async () => await aria2Integration.pauseQueueAsync();
const getAsync = async () => await aria2Integration.getClientJobsAndStatusAsync(); const getAsync = async () => await aria2Integration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(actAsync()).resolves.not.toThrow(); await expect(actAsync()).resolves.not.toThrow();
@@ -62,7 +62,7 @@ describe("Aria2 integration", () => {
const aria2Integration = createAria2Intergration(startedContainer, API_KEY); const aria2Integration = createAria2Intergration(startedContainer, API_KEY);
// Act // Act
const getAsync = async () => await aria2Integration.getClientJobsAndStatusAsync(); const getAsync = async () => await aria2Integration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(getAsync()).resolves.not.toThrow(); await expect(getAsync()).resolves.not.toThrow();
@@ -81,7 +81,7 @@ describe("Aria2 integration", () => {
await aria2AddItemAsync(startedContainer, API_KEY, aria2Integration); await aria2AddItemAsync(startedContainer, API_KEY, aria2Integration);
// Act // Act
const getAsync = async () => await aria2Integration.getClientJobsAndStatusAsync(); const getAsync = async () => await aria2Integration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(getAsync()).resolves.not.toThrow(); await expect(getAsync()).resolves.not.toThrow();
@@ -104,7 +104,7 @@ describe("Aria2 integration", () => {
await expect(actAsync()).resolves.not.toThrow(); await expect(actAsync()).resolves.not.toThrow();
// NzbGet is slow and we wait for a second before querying the items. Test was flaky without this. // NzbGet is slow and we wait for a second before querying the items. Test was flaky without this.
await new Promise((resolve) => setTimeout(resolve, 1000)); await new Promise((resolve) => setTimeout(resolve, 1000));
const result = await aria2Integration.getClientJobsAndStatusAsync(); const result = await aria2Integration.getClientJobsAndStatusAsync({ limit: 99 });
expect(result.items).toHaveLength(0); expect(result.items).toHaveLength(0);
// Cleanup // Cleanup
@@ -153,7 +153,7 @@ const aria2AddItemAsync = async (container: StartedTestContainer, apiKey: string
const { const {
items: [item], items: [item],
} = await integration.getClientJobsAndStatusAsync(); } = await integration.getClientJobsAndStatusAsync({ limit: 99 });
if (!item) { if (!item) {
throw new Error("No item found"); throw new Error("No item found");
+6 -6
View File
@@ -69,7 +69,7 @@ describe("Nzbget integration", () => {
// Acts // Acts
const actAsync = async () => await nzbGetIntegration.pauseQueueAsync(); const actAsync = async () => await nzbGetIntegration.pauseQueueAsync();
const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync(); const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(actAsync()).resolves.not.toThrow(); await expect(actAsync()).resolves.not.toThrow();
@@ -87,7 +87,7 @@ describe("Nzbget integration", () => {
// Acts // Acts
const actAsync = async () => await nzbGetIntegration.resumeQueueAsync(); const actAsync = async () => await nzbGetIntegration.resumeQueueAsync();
const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync(); const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(actAsync()).resolves.not.toThrow(); await expect(actAsync()).resolves.not.toThrow();
@@ -105,7 +105,7 @@ describe("Nzbget integration", () => {
const nzbGetIntegration = createNzbGetIntegration(startedContainer, username, password); const nzbGetIntegration = createNzbGetIntegration(startedContainer, username, password);
// Act // Act
const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync(); const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(getAsync()).resolves.not.toThrow(); await expect(getAsync()).resolves.not.toThrow();
@@ -124,7 +124,7 @@ describe("Nzbget integration", () => {
await nzbGetAddItemAsync(startedContainer, username, password, nzbGetIntegration); await nzbGetAddItemAsync(startedContainer, username, password, nzbGetIntegration);
// Act // Act
const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync(); const getAsync = async () => await nzbGetIntegration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(getAsync()).resolves.not.toThrow(); await expect(getAsync()).resolves.not.toThrow();
@@ -147,7 +147,7 @@ describe("Nzbget integration", () => {
await expect(actAsync()).resolves.not.toThrow(); await expect(actAsync()).resolves.not.toThrow();
// NzbGet is slow and we wait for a second before querying the items. Test was flaky without this. // NzbGet is slow and we wait for a second before querying the items. Test was flaky without this.
await new Promise((resolve) => setTimeout(resolve, 1000)); await new Promise((resolve) => setTimeout(resolve, 1000));
const result = await nzbGetIntegration.getClientJobsAndStatusAsync(); const result = await nzbGetIntegration.getClientJobsAndStatusAsync({ limit: 99 });
expect(result.items).toHaveLength(0); expect(result.items).toHaveLength(0);
// Cleanup // Cleanup
@@ -209,7 +209,7 @@ const nzbGetAddItemAsync = async (
const { const {
items: [item], items: [item],
} = await integration.getClientJobsAndStatusAsync(); } = await integration.getClientJobsAndStatusAsync({ limit: 99 });
if (!item) { if (!item) {
throw new Error("No item found"); throw new Error("No item found");
+8 -8
View File
@@ -67,7 +67,7 @@ describe("Sabnzbd integration", () => {
// Acts // Acts
const actAsync = async () => await sabnzbdIntegration.pauseQueueAsync(); const actAsync = async () => await sabnzbdIntegration.pauseQueueAsync();
const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync(); const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(actAsync()).resolves.not.toThrow(); await expect(actAsync()).resolves.not.toThrow();
@@ -85,7 +85,7 @@ describe("Sabnzbd integration", () => {
// Acts // Acts
const actAsync = async () => await sabnzbdIntegration.resumeQueueAsync(); const actAsync = async () => await sabnzbdIntegration.resumeQueueAsync();
const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync(); const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(actAsync()).resolves.not.toThrow(); await expect(actAsync()).resolves.not.toThrow();
@@ -103,7 +103,7 @@ describe("Sabnzbd integration", () => {
const sabnzbdIntegration = createSabnzbdIntegration(startedContainer, DEFAULT_API_KEY); const sabnzbdIntegration = createSabnzbdIntegration(startedContainer, DEFAULT_API_KEY);
// Act // Act
const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync(); const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(getAsync()).resolves.not.toThrow(); await expect(getAsync()).resolves.not.toThrow();
@@ -122,7 +122,7 @@ describe("Sabnzbd integration", () => {
await sabNzbdAddItemAsync(startedContainer, DEFAULT_API_KEY, sabnzbdIntegration); await sabNzbdAddItemAsync(startedContainer, DEFAULT_API_KEY, sabnzbdIntegration);
// Act // Act
const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync(); const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(getAsync()).resolves.not.toThrow(); await expect(getAsync()).resolves.not.toThrow();
@@ -140,7 +140,7 @@ describe("Sabnzbd integration", () => {
// Act // Act
const actAsync = async () => await sabnzbdIntegration.pauseItemAsync(item); const actAsync = async () => await sabnzbdIntegration.pauseItemAsync(item);
const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync(); const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(getAsync()).resolves.toMatchObject({ items: [{ ...item, state: "downloading" }] }); await expect(getAsync()).resolves.toMatchObject({ items: [{ ...item, state: "downloading" }] });
@@ -160,7 +160,7 @@ describe("Sabnzbd integration", () => {
// Act // Act
const actAsync = async () => await sabnzbdIntegration.resumeItemAsync(item); const actAsync = async () => await sabnzbdIntegration.resumeItemAsync(item);
const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync(); const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(getAsync()).resolves.toMatchObject({ items: [{ ...item, state: "paused" }] }); await expect(getAsync()).resolves.toMatchObject({ items: [{ ...item, state: "paused" }] });
@@ -180,7 +180,7 @@ describe("Sabnzbd integration", () => {
// Act - fromDisk already doesn't work for sabnzbd, so only test deletion itself. // Act - fromDisk already doesn't work for sabnzbd, so only test deletion itself.
const actAsync = async () => const actAsync = async () =>
await sabnzbdIntegration.deleteItemAsync({ ...item, progress: 0 } as DownloadClientItem, false); await sabnzbdIntegration.deleteItemAsync({ ...item, progress: 0 } as DownloadClientItem, false);
const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync(); const getAsync = async () => await sabnzbdIntegration.getClientJobsAndStatusAsync({ limit: 99 });
// Assert // Assert
await expect(actAsync()).resolves.not.toThrow(); await expect(actAsync()).resolves.not.toThrow();
@@ -242,7 +242,7 @@ const sabNzbdAddItemAsync = async (
for (let i = 0; i < 5; i++) { for (let i = 0; i < 5; i++) {
const { const {
items: [item], items: [item],
} = await integration.getClientJobsAndStatusAsync(); } = await integration.getClientJobsAndStatusAsync({ limit: 99 });
if (item) return item; if (item) return item;
} }
// Throws if it can't find the item // Throws if it can't find the item
+2 -2
View File
@@ -27,13 +27,13 @@
"ioredis": "5.6.1", "ioredis": "5.6.1",
"superjson": "2.2.2", "superjson": "2.2.2",
"winston": "3.17.0", "winston": "3.17.0",
"zod": "^3.24.4" "zod": "^3.25.30"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+4 -4
View File
@@ -33,19 +33,19 @@
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@mantine/core": "^8.0.1", "@mantine/core": "^8.0.2",
"@tabler/icons-react": "^3.31.0", "@tabler/icons-react": "^3.33.0",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"next": "15.3.2", "next": "15.3.2",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"zod": "^3.24.4" "zod": "^3.25.30"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
@@ -1,5 +1,4 @@
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import Image from "next/image";
import { Button, Card, Center, Grid, Input, Stack, Text } from "@mantine/core"; import { Button, Card, Center, Grid, Input, Stack, Text } from "@mantine/core";
import { IconPlus, IconSearch } from "@tabler/icons-react"; import { IconPlus, IconSearch } from "@tabler/icons-react";
@@ -23,7 +22,7 @@ export const AppSelectModal = createModal<AppSelectModalProps>(({ actions, inner
() => () =>
apps apps
.filter((app) => app.name.toLowerCase().includes(search.toLowerCase())) .filter((app) => app.name.toLowerCase().includes(search.toLowerCase()))
.sort((a, b) => a.name.localeCompare(b.name)), .sort((appA, appB) => appA.name.localeCompare(appB.name)),
[apps, search], [apps, search],
); );
@@ -88,7 +87,7 @@ export const AppSelectModal = createModal<AppSelectModalProps>(({ actions, inner
<Stack justify="space-between" h="100%"> <Stack justify="space-between" h="100%">
<Stack gap="xs"> <Stack gap="xs">
<Center> <Center>
<Image src={app.iconUrl || ""} alt={app.name} width={24} height={24} /> <img src={app.iconUrl} alt={app.name} width={24} height={24} />
</Center> </Center>
<Text lh={1.2} style={{ whiteSpace: "normal" }} ta="center"> <Text lh={1.2} style={{ whiteSpace: "normal" }} ta="center">
{app.name} {app.name}
+3 -3
View File
@@ -24,15 +24,15 @@
"dependencies": { "dependencies": {
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@mantine/core": "^8.0.1", "@mantine/core": "^8.0.2",
"@mantine/hooks": "^8.0.1", "@mantine/hooks": "^8.0.2",
"react": "19.1.0" "react": "19.1.0"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+3 -3
View File
@@ -24,14 +24,14 @@
"prettier": "@homarr/prettier-config", "prettier": "@homarr/prettier-config",
"dependencies": { "dependencies": {
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@mantine/notifications": "^8.0.1", "@mantine/notifications": "^8.0.2",
"@tabler/icons-react": "^3.31.0" "@tabler/icons-react": "^3.33.0"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+4 -4
View File
@@ -37,14 +37,14 @@
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0",
"@mantine/core": "^8.0.1", "@mantine/core": "^8.0.2",
"@mantine/hooks": "^8.0.1", "@mantine/hooks": "^8.0.2",
"adm-zip": "0.5.16", "adm-zip": "0.5.16",
"next": "15.3.2", "next": "15.3.2",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"superjson": "2.2.2", "superjson": "2.2.2",
"zod": "^3.24.4", "zod": "^3.25.30",
"zod-form-data": "^2.0.7" "zod-form-data": "^2.0.7"
}, },
"devDependencies": { "devDependencies": {
@@ -52,7 +52,7 @@
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"@types/adm-zip": "0.5.7", "@types/adm-zip": "0.5.7",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
@@ -77,6 +77,7 @@ const optionMapping: OptionMapping = {
descendingDefaultSort: () => false, descendingDefaultSort: () => false,
showCompletedUsenet: () => true, showCompletedUsenet: () => true,
showCompletedHttp: () => true, showCompletedHttp: () => true,
limitPerIntegration: () => undefined,
}, },
weather: { weather: {
forecastDayCount: (oldOptions) => oldOptions.forecastDays, forecastDayCount: (oldOptions) => oldOptions.forecastDays,
@@ -156,6 +157,21 @@ const optionMapping: OptionMapping = {
defaultTab: (oldOptions) => ("defaultTabState" in oldOptions ? oldOptions.defaultTabState : undefined), defaultTab: (oldOptions) => ("defaultTabState" in oldOptions ? oldOptions.defaultTabState : undefined),
sectionIndicatorRequirement: (oldOptions) => sectionIndicatorRequirement: (oldOptions) =>
"sectionIndicatorColor" in oldOptions ? oldOptions.sectionIndicatorColor : undefined, "sectionIndicatorColor" in oldOptions ? oldOptions.sectionIndicatorColor : undefined,
showUptime: () => undefined,
visibleClusterSections: (oldOptions) => {
if (!("showNode" in oldOptions)) return undefined;
const oldKeys = {
showNode: "node" as const,
showLXCs: "lxc" as const,
showVM: "qemu" as const,
showStorage: "storage" as const,
} satisfies Partial<Record<keyof typeof oldOptions, string>>;
return objectEntries(oldKeys)
.filter(([key]) => oldOptions[key])
.map(([_, section]) => section);
},
}, },
mediaTranscoding: { mediaTranscoding: {
defaultView: (oldOptions) => oldOptions.defaultView, defaultView: (oldOptions) => oldOptions.defaultView,
+2 -2
View File
@@ -23,13 +23,13 @@
"prettier": "@homarr/prettier-config", "prettier": "@homarr/prettier-config",
"dependencies": { "dependencies": {
"@homarr/common": "workspace:^0.1.0", "@homarr/common": "workspace:^0.1.0",
"zod": "^3.24.4" "zod": "^3.25.30"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+1 -1
View File
@@ -30,7 +30,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+1 -1
View File
@@ -33,7 +33,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+2 -2
View File
@@ -30,14 +30,14 @@
"@homarr/log": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0",
"@homarr/redis": "workspace:^0.1.0", "@homarr/redis": "workspace:^0.1.0",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"octokit": "^4.1.3", "octokit": "^5.0.2",
"superjson": "2.2.2" "superjson": "2.2.2"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+4 -2
View File
@@ -13,8 +13,10 @@ export const calendarMonthRequestHandler = createCachedIntegrationRequestHandler
>({ >({
async requestAsync(integration, input) { async requestAsync(integration, input) {
const integrationInstance = await createIntegrationAsync(integration); const integrationInstance = await createIntegrationAsync(integration);
const startDate = dayjs().year(input.year).month(input.month).startOf("month"); // Calendar component shows up to 6 days before and after the month, for example if 1. of january is sunday, it shows the last 6 days of december.
const endDate = startDate.clone().endOf("month"); const startDate = dayjs().year(input.year).month(input.month).startOf("month").subtract(6, "days");
const endDate = dayjs().year(input.year).month(input.month).endOf("month").add(6, "days");
return await integrationInstance.getCalendarEventsAsync( return await integrationInstance.getCalendarEventsAsync(
startDate.toDate(), startDate.toDate(),
endDate.toDate(), endDate.toDate(),
+80
View File
@@ -0,0 +1,80 @@
import dayjs from "dayjs";
import type { ContainerInfo, ContainerStats } from "dockerode";
import { db, like, or } from "@homarr/db";
import { icons } from "@homarr/db/schema";
import type { ContainerState } from "../../docker/src";
import { DockerSingleton } from "../../docker/src";
import { createCachedWidgetRequestHandler } from "./lib/cached-widget-request-handler";
export const dockerContainersRequestHandler = createCachedWidgetRequestHandler({
queryKey: "dockerContainersResult",
widgetKind: "dockerContainers",
async requestAsync() {
const containers = await getContainersWithStatsAsync();
return containers;
},
cacheDuration: dayjs.duration(20, "seconds"),
});
const dockerInstances = DockerSingleton.getInstances();
const extractImage = (container: ContainerInfo) => container.Image.split("/").at(-1)?.split(":").at(0) ?? "";
async function getContainersWithStatsAsync() {
const containers = await Promise.all(
dockerInstances.map(async ({ instance, host }) => {
const instanceContainers = await instance.listContainers({ all: true });
return instanceContainers.map((container) => ({
...container,
instance: host,
}));
}),
).then((res) => res.flat());
const likeQueries = containers.map((container) => like(icons.name, `%${extractImage(container)}%`));
const dbIcons =
likeQueries.length > 0
? await db.query.icons.findMany({
where: or(...likeQueries),
})
: [];
const containerStatsPromises = containers.map(async (container) => {
const instance = dockerInstances.find(({ host }) => host === container.instance)?.instance;
if (!instance) return null;
const stats = await instance.getContainer(container.Id).stats({ stream: false });
return {
id: container.Id,
name: container.Names[0]?.split("/")[1] ?? "Unknown",
state: container.State as ContainerState,
iconUrl:
dbIcons.find((icon) => {
const extractedImage = extractImage(container);
if (!extractedImage) return false;
return icon.name.toLowerCase().includes(extractedImage.toLowerCase());
})?.url ?? null,
cpuUsage: calculateCpuUsage(stats),
memoryUsage: stats.memory_stats.usage,
image: container.Image,
ports: container.Ports,
};
});
return (await Promise.all(containerStatsPromises)).filter((container) => container !== null);
}
function calculateCpuUsage(stats: ContainerStats): number {
const cpuDelta = stats.cpu_stats.cpu_usage.total_usage - stats.precpu_stats.cpu_usage.total_usage;
const systemDelta = stats.cpu_stats.system_cpu_usage - stats.precpu_stats.system_cpu_usage;
const numberOfCpus = stats.cpu_stats.online_cpus || 1;
if (systemDelta === 0) return 0;
return (cpuDelta / systemDelta) * numberOfCpus * 100;
}
+3 -3
View File
@@ -9,11 +9,11 @@ import { createCachedIntegrationRequestHandler } from "./lib/cached-integration-
export const downloadClientRequestHandler = createCachedIntegrationRequestHandler< export const downloadClientRequestHandler = createCachedIntegrationRequestHandler<
DownloadClientJobsAndStatus, DownloadClientJobsAndStatus,
IntegrationKindByCategory<"downloadClient">, IntegrationKindByCategory<"downloadClient">,
Record<string, never> { limit: number }
>({ >({
async requestAsync(integration, _input) { async requestAsync(integration, input) {
const integrationInstance = await createIntegrationAsync(integration); const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getClientJobsAndStatusAsync(); return await integrationInstance.getClientJobsAndStatusAsync(input);
}, },
cacheDuration: dayjs.duration(5, "seconds"), cacheDuration: dayjs.duration(5, "seconds"),
queryKey: "downloadClientJobStatus", queryKey: "downloadClientJobStatus",
+1 -1
View File
@@ -29,7 +29,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+2 -2
View File
@@ -26,7 +26,7 @@
"@homarr/api": "workspace:^0.1.0", "@homarr/api": "workspace:^0.1.0",
"@homarr/db": "workspace:^0.1.0", "@homarr/db": "workspace:^0.1.0",
"@homarr/server-settings": "workspace:^0.1.0", "@homarr/server-settings": "workspace:^0.1.0",
"@mantine/dates": "^8.0.1", "@mantine/dates": "^8.0.2",
"next": "15.3.2", "next": "15.3.2",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0" "react-dom": "19.1.0"
@@ -35,7 +35,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+6 -6
View File
@@ -33,11 +33,11 @@
"@homarr/settings": "workspace:^0.1.0", "@homarr/settings": "workspace:^0.1.0",
"@homarr/translation": "workspace:^0.1.0", "@homarr/translation": "workspace:^0.1.0",
"@homarr/ui": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0",
"@mantine/core": "^8.0.1", "@mantine/core": "^8.0.2",
"@mantine/hooks": "^8.0.1", "@mantine/hooks": "^8.0.2",
"@mantine/spotlight": "^8.0.1", "@mantine/spotlight": "^8.0.2",
"@tabler/icons-react": "^3.31.0", "@tabler/icons-react": "^3.33.0",
"jotai": "^2.12.4", "jotai": "^2.12.5",
"next": "15.3.2", "next": "15.3.2",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
@@ -47,7 +47,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+1 -1
View File
@@ -41,7 +41,7 @@
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",
"@homarr/prettier-config": "workspace:^0.1.0", "@homarr/prettier-config": "workspace:^0.1.0",
"@homarr/tsconfig": "workspace:^0.1.0", "@homarr/tsconfig": "workspace:^0.1.0",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "Comprova la connexió i crea", "create": "Comprova la connexió i crea",
"edit": "Comprova la connexió i desa" "edit": "Comprova la connexió i desa"
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "El botó \"Desa\" s'habilita quan la connexió s'estableix correctament", "alertNotice": "El botó \"Desa\" s'habilita quan la connexió s'estableix correctament",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "", "cancel": "",
"delete": "", "delete": "",
"discard": "", "discard": "",
"close": "",
"confirm": "", "confirm": "",
"continue": "", "continue": "",
"previous": "", "previous": "",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "" "label": ""
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "" "label": ""
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "" "label": ""
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "", "label": "",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "测试连接并创建", "create": "测试连接并创建",
"edit": "测试连接并保存" "edit": "测试连接并保存"
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "成功建立连接后保存按钮将启用", "alertNotice": "成功建立连接后保存按钮将启用",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "取消", "cancel": "取消",
"delete": "删除", "delete": "删除",
"discard": "Discard", "discard": "Discard",
"close": "",
"confirm": "确认", "confirm": "确认",
"continue": "继续", "continue": "继续",
"previous": "上一步", "previous": "上一步",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "显示内存信息" "label": "显示内存信息"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "显示文件系统信息" "label": "显示文件系统信息"
}, },
"defaultTab": { "defaultTab": {
"label": "默认标签" "label": "默认标签"
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "部分指标要求" "label": "部分指标要求"
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "城市/邮编", "query": "城市/邮编",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "使用过滤器来计算比率" "label": "使用过滤器来计算比率"
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "网络控制器" "label": "网络控制器"
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "已更新 {when}", "updated": "已更新 {when}",
"search": "搜索 {count} 容器", "search": "搜索 {count} 容器",
"selected": "{totalCount} 容器的 {selectCount}" "selected": "{totalCount} 容器的 {selectCount}",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "废弃" "dead": "废弃"
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "镜像" "label": "镜像"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "开始", "label": "开始",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "日志" "label": "日志"
}, },
"certificates": { "certificates": {
"label": "证书" "label": "证书",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "可信证书", "title": "可信证书",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "到期时间 {when}" "expires": "到期时间 {when}",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "无法删除证书" "message": "无法删除证书"
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "Otestovat připojení a vytvořit", "create": "Otestovat připojení a vytvořit",
"edit": "Otestovat připojení a uložit" "edit": "Otestovat připojení a uložit"
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "", "alertNotice": "",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Zrušit", "cancel": "Zrušit",
"delete": "Odstranit", "delete": "Odstranit",
"discard": "Zahodit", "discard": "Zahodit",
"close": "",
"confirm": "Potvrdit", "confirm": "Potvrdit",
"continue": "Pokračovat", "continue": "Pokračovat",
"previous": "Zpět", "previous": "Zpět",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "Zobrazit informace o paměti" "label": "Zobrazit informace o paměti"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "Zobrazit informace o souborovém systému" "label": "Zobrazit informace o souborovém systému"
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "Obraz" "label": "Obraz"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "Spustit", "label": "Spustit",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+258 -51
View File
@@ -702,6 +702,132 @@
"create": "Test forbindelse og opret", "create": "Test forbindelse og opret",
"edit": "Test forbindelse og gem" "edit": "Test forbindelse og gem"
}, },
"error": {
"common": {
"cause": {
"title": "Årsag med flere detaljer"
}
},
"unknown": {
"title": "Ukendt fejl",
"description": "En ukendt fejl opstod, åbn årsagen nedenfor for at se flere detaljer"
},
"parse": {
"title": "Parsingfejl",
"description": "Svaret kunne ikke fortolkes. Kontroller, at URL'en peger på tjenestens grundlæggende URL."
},
"authorization": {
"title": "Godkendelsesfejl",
"description": "Anmodningen blev ikke godkendt. Kontroller, at legitimationsoplysningerne er korrekte og at du har dem konfigureret med nok tilladelser."
},
"statusCode": {
"title": "Svar fejl",
"description": "Modtaget uventet {statusCode} ({reason}) svar fra <url></url>. Kontroller, at URL'en peger på basis-URL'en for integrationen.",
"otherDescription": "Modtaget uventet {statusCode} svar fra <url></url>. Kontroller, at URLen peger på den grundlæggende URL for integrationen.",
"reason": {
"badRequest": "Ugyldig forespørgsel",
"notFound": "Ikke fundet",
"tooManyRequests": "For mange forespørgsler",
"internalServerError": "Intern serverfejl",
"serviceUnavailable": "Tjeneste ikke tilgængelig",
"gatewayTimeout": "Gateway-timeout"
}
},
"certificate": {
"title": "Certifikatfejl",
"description": {
"expired": "Certifikatet er udløbet.",
"notYetValid": "Certifikatet er ikke gyldigt endnu.",
"untrusted": "Der er ikke tillid til certifikatet.",
"hostnameMismatch": "Certifikatets værtsnavn matcher ikke URL'en."
},
"alert": {
"permission": {
"title": "Ikke tilstrækkelige tilladelser",
"message": "Du har ikke tilladelse til at stole på eller uploade certifikater. Kontakt venligst din administrator for at uploade det nødvendige rodcertifikat."
},
"hostnameMismatch": {
"title": "Værtsnavn matcher ikke",
"message": "Værtsnavnet i certifikatet matcher ikke det værtsnavn du forbinder til. Dette kan indikere en sikkerhedsrisiko, men du kan stadig vælge at stole på dette certifikat."
},
"extract": {
"title": "Ekstraktion af CA-certifikat mislykkedes",
"message": "Kun selvsignerede certifikater uden kæde kan hentes automatisk. Hvis du bruger et selvsigneret certifikat, skal du sørge for at uploade CA-certifikatet manuelt. Du kan finde instruktioner om, hvordan du gør dette <docsLink></docsLink>."
}
},
"action": {
"retry": {
"label": "Gentag oprettelse"
},
"trust": {
"label": "Stol på certifikat"
},
"upload": {
"label": "Upload certifikat"
}
},
"hostnameMismatch": {
"confirm": {
"title": "Stol på uoverensstemmelse mellem værtsnavn",
"message": "Er du sikker på du vil have tillid til certifikatet med et værtsnavn uoverensstemmelse?"
},
"notification": {
"success": {
"title": "Betroet certifikat",
"message": "Tilføjet værtsnavn til liste over betroede certifikater"
},
"error": {
"title": "Kunne ikke stole på certifikat",
"message": "Certifikatet med et værtsnavn mismatch kunne ikke stoles på"
}
}
},
"selfSigned": {
"confirm": {
"title": "Stol på selvsigneret certifikat",
"message": "Er du sikker på, at du vil stole på dette selvsignerede certifikat?"
},
"notification": {
"success": {
"title": "Betroet certifikat",
"message": "Tilføjet certifikat til liste over betroede certifikater"
},
"error": {
"title": "Kunne ikke stole på certifikat",
"message": "Kunne ikke tilføje certifikat til listen over betroede certifikater"
}
}
},
"details": {
"title": "Detaljer",
"description": "Gennemgå certifikatoplysningerne, før du beslutter dig for at stole på den.",
"content": {
"action": "Vis indhold",
"title": "PEM Certifikat"
}
}
},
"request": {
"title": "Anmodningsfejl",
"description": {
"connection": {
"hostUnreachable": "Serveren kunne ikke nås. Dette betyder normalt, at værten er offline eller ikke kan nås fra dit netværk.",
"networkUnreachable": "Netværket er ikke tilgængeligt. Tjek venligst din internetforbindelse eller netværkskonfiguration.",
"refused": "Serveren nægtede forbindelsen. Den kører muligvis ikke eller afviser forespørgsler på den angivne port.",
"reset": "Forbindelsen blev uventet lukket af serveren. Dette kan ske hvis serveren er ustabil eller genstartet."
},
"dns": {
"notFound": "Serveradressen kunne ikke findes. Tjek venligst URL'en for stave eller ugyldige domænenavne.",
"timeout": "DNS-opslag fik timeout. Dette kan være et midlertidigt problem - prøv igen om et øjeblik.",
"noAnswer": "DNS-serveren returnerede ikke et gyldigt svar. Domænet findes måske men har ingen gyldige poster."
},
"timeout": {
"aborted": "Anmodningen blev afbrudt før den kunne fuldføres. Dette kan skyldes en bruger handling eller system timeout.",
"timeout": "Forespørgslen tog for lang tid at fuldføre og fik timeout. Tjek dit netværk eller prøv igen senere."
}
}
}
},
"alertNotice": "Gem-knappen er aktiveret, når en vellykket forbindelse er etableret", "alertNotice": "Gem-knappen er aktiveret, når en vellykket forbindelse er etableret",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Annuller", "cancel": "Annuller",
"delete": "Slet", "delete": "Slet",
"discard": "Kassér", "discard": "Kassér",
"close": "Luk",
"confirm": "Bekræft", "confirm": "Bekræft",
"continue": "Forsæt", "continue": "Forsæt",
"previous": "Forrige", "previous": "Forrige",
@@ -1093,7 +1220,7 @@
"label": "Integrationer" "label": "Integrationer"
}, },
"title": { "title": {
"label": "" "label": "Titel"
}, },
"customCssClasses": { "customCssClasses": {
"label": "Brugerdefinerede CSS-klasser" "label": "Brugerdefinerede CSS-klasser"
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "Vis hukommelsesoplysninger" "label": "Vis hukommelsesoplysninger"
}, },
"showUptime": {
"label": "Vis Oppetid"
},
"fileSystem": { "fileSystem": {
"label": "Vis information om filsystemet" "label": "Vis information om filsystemet"
}, },
"defaultTab": { "defaultTab": {
"label": "Standard fane" "label": "Standard fane"
}, },
"visibleClusterSections": {
"label": "Synlige klynge sektioner"
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "Sektion indikator er et krav" "label": "Sektion indikator er et krav"
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "Docker statistik",
"description": "Statistik for dine containere (Denne widget kan kun tilføjes med administratorrettigheder)",
"option": {},
"error": {
"internalServerError": "Kunne ikke hente containerstatistik"
}
},
"common": { "common": {
"location": { "location": {
"query": "By / Postnummer", "query": "By / Postnummer",
@@ -1771,8 +1912,8 @@
"description": "Vis de aktuelle streams på dine medieservere", "description": "Vis de aktuelle streams på dine medieservere",
"option": { "option": {
"showOnlyPlaying": { "showOnlyPlaying": {
"label": "", "label": "Vis kun hvad der aktuelt afspilles",
"description": "" "description": "Deaktivering af dette vil ikke virke for plex"
} }
}, },
"items": { "items": {
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "Brug filteret til at beregne forholdet" "label": "Brug filteret til at beregne forholdet"
},
"limitPerIntegration": {
"label": "Begræns elementer pr. integration",
"description": "Dette vil begrænse antallet af elementer vist pr. integration, ikke globalt"
} }
}, },
"errors": { "errors": {
@@ -1950,7 +2095,7 @@
"approved": "Godkendt", "approved": "Godkendt",
"declined": "Afvist", "declined": "Afvist",
"failed": "Mislykket", "failed": "Mislykket",
"completed": "" "completed": "Fuldført"
}, },
"toBeDetermined": "TBD" "toBeDetermined": "TBD"
}, },
@@ -2054,94 +2199,94 @@
} }
}, },
"releases": { "releases": {
"name": "", "name": "Udgivelser",
"description": "", "description": "Viser en liste over den aktuelle version af de givne depoter med den givne version regex.",
"option": { "option": {
"newReleaseWithin": { "newReleaseWithin": {
"label": "", "label": "Ny Udgivelse Inden",
"description": "" "description": "Anvendelseseksempel: 1w (1 uge), 10M (10 måneder). Accepterede enhedstyper h (timer), d (dage), w (uger), M (måneder), y (år). Lad være tom for ingen fremhævning af nye udgivelser."
}, },
"staleReleaseWithin": { "staleReleaseWithin": {
"label": "", "label": "Gamle Udgivelse Indenfor",
"description": "" "description": "Anvendelseseksempel: 1w (1 uge), 10M (10 måneder). Accepterede enhedstyper h (timer), d (dage), w (uger), M (måneder), y (år). Lad være tom for ingen fremhævning af forældede udgivelser."
}, },
"showOnlyHighlighted": { "showOnlyHighlighted": {
"label": "", "label": "Vis Kun Fremhævede",
"description": "" "description": "Vis kun nye eller forældede udgivelser. Som pr ovenfor."
}, },
"showDetails": { "showDetails": {
"label": "" "label": "Vis detaljer"
}, },
"topReleases": { "topReleases": {
"label": "", "label": "Top Udgivelser",
"description": "" "description": "Det maksimale antal seneste udgivelser at vise. Nul betyder ingen grænse."
}, },
"repositories": { "repositories": {
"label": "", "label": "Repositories",
"addRRepository": { "addRRepository": {
"label": "" "label": "Tilføj repository"
}, },
"provider": { "provider": {
"label": "" "label": "Udbyder"
}, },
"identifier": { "identifier": {
"label": "", "label": "Identifikator",
"placeholder": "" "placeholder": "Navn eller ejer/navn"
}, },
"name": { "name": {
"label": "" "label": "Navn"
}, },
"versionFilter": { "versionFilter": {
"label": "", "label": "Versionsfilter",
"prefix": { "prefix": {
"label": "" "label": "Præfiks"
}, },
"precision": { "precision": {
"label": "", "label": "Præcision",
"options": { "options": {
"none": "" "none": "Ingen"
} }
}, },
"suffix": { "suffix": {
"label": "" "label": "Suffiks"
}, },
"regex": { "regex": {
"label": "" "label": "Regulært Udtryk"
} }
}, },
"edit": { "edit": {
"label": "" "label": "Rediger"
}, },
"editForm": { "editForm": {
"title": "", "title": "Rediger Repository",
"cancel": { "cancel": {
"label": "" "label": "Annuller"
}, },
"confirm": { "confirm": {
"label": "" "label": "Bekræft"
} }
}, },
"example": { "example": {
"label": "" "label": "Eksempel"
}, },
"invalid": "" "invalid": "Ugyldig repository definition, tjek venligst værdierne"
} }
}, },
"not-found": "", "not-found": "Ikke fundet",
"pre-release": "", "pre-release": "Pre-Release",
"archived": "", "archived": "Arkiveret",
"forked": "", "forked": "Forked",
"starsCount": "", "starsCount": "Stjerner",
"forksCount": "", "forksCount": "Forks",
"issuesCount": "", "issuesCount": "Åbne Problemer",
"openProjectPage": "", "openProjectPage": "Åbn Projektside",
"openReleasePage": "", "openReleasePage": "Åbn Udgivelsesside",
"releaseDescription": "", "releaseDescription": "Udgivelse Beskrivelse",
"created": "", "created": "Oprettet",
"error": { "error": {
"label": "", "label": "Fejl",
"options": { "options": {
"noMatchingVersion": "" "noMatchingVersion": "Ingen matchende version fundet"
} }
} }
}, },
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "Netværkskontroller" "label": "Netværkskontroller"
},
"dockerContainers": {
"label": "Docker containers"
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "Opdateret {when}", "updated": "Opdateret {when}",
"search": "Søg {count} containere", "search": "Søg {count} containere",
"selected": "{selectCount} af {totalCount} containere valgt" "selected": "{selectCount} af {totalCount} containere valgt",
"footer": "Total {count} containere"
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "Død" "dead": "Død"
} }
}, },
"stats": {
"cpu": {
"label": "CPU"
},
"memory": {
"label": "Hukommelse"
}
},
"containerImage": { "containerImage": {
"label": "Billede" "label": "Billede"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "Handlinger",
"start": { "start": {
"label": "Start", "label": "Start",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "Logs" "label": "Logs"
}, },
"certificates": { "certificates": {
"label": "Certifikater" "label": "Certifikater",
"hostnames": {
"label": "Værtsnavne"
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": "Værtsnavn"
},
"subject": {
"label": "Emne"
},
"issuer": {
"label": "Udsteder"
},
"validFrom": {
"label": "Gyldig fra"
},
"validTo": {
"label": "Gyldig til"
},
"serialNumber": {
"label": "Serienummer"
},
"fingerprint": {
"label": "Fingeraftryk"
}
},
"page": { "page": {
"list": { "list": {
"title": "Betroede certifikater", "title": "Betroede certifikater",
@@ -3902,10 +4086,19 @@
"title": "Der er endnu ingen certifikater" "title": "Der er endnu ingen certifikater"
}, },
"invalid": { "invalid": {
"title": "", "title": "Ugyldigt certifikat",
"description": "" "description": "Kunne ikke fortolke certifikat"
}, },
"expires": "Udløber {when}" "expires": "Udløber {when}",
"toHostnames": "Betroede værtsnavne"
},
"hostnames": {
"title": "Betroet certifikat værtsnavne",
"description": "Nogle certifikater tillader ikke det specifikke domæne Homarr bruger til at anmode om dem, på grund af dette alle betroede værtsnavne med deres certifikat thumbprints bruges til at omgå disse restriktioner.",
"noResults": {
"title": "Der er endnu ingen værtsnavne"
},
"toCertificates": "Certifikater"
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "Certifikatet kunne ikke slettes" "message": "Certifikatet kunne ikke slettes"
} }
} }
},
"removeHostname": {
"label": "Fjern betroet værtsnavn",
"confirm": "Er du sikker på du vil fjerne dette betroede værtsnavn? Dette kan få nogle integrationer til at stoppe med at virke.",
"notification": {
"success": {
"title": "Værtsnavn fjernet",
"message": "Værtsnavnet blev fjernet korrekt"
},
"error": {
"title": "Værtsnavn ikke fjernet",
"message": "Værtsnavnet kunne ikke fjernes"
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "Verbindig teste und erstäue", "create": "Verbindig teste und erstäue",
"edit": "Verbinding teste und spichere" "edit": "Verbinding teste und spichere"
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "Dr Spicherknopf isch aktiv sobald d Verbindig het chönne hergstellt werde", "alertNotice": "Dr Spicherknopf isch aktiv sobald d Verbindig het chönne hergstellt werde",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Abbrechen", "cancel": "Abbrechen",
"delete": "Löschen", "delete": "Löschen",
"discard": "Verwerfen", "discard": "Verwerfen",
"close": "",
"confirm": "Bestätigen", "confirm": "Bestätigen",
"continue": "Fortfahren", "continue": "Fortfahren",
"previous": "Zurück", "previous": "Zurück",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "Speicher-Info anzeigen" "label": "Speicher-Info anzeigen"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "Dateisystem Info anzeigen" "label": "Dateisystem Info anzeigen"
}, },
"defaultTab": { "defaultTab": {
"label": "Standard Tab" "label": "Standard Tab"
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "Anforderung der Sektionsindikatoren" "label": "Anforderung der Sektionsindikatoren"
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "Stadt / Postleitzahl", "query": "Stadt / Postleitzahl",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "Filter zur Berechnung des Verhältnisses verwenden" "label": "Filter zur Berechnung des Verhältnisses verwenden"
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "Aktualisiert {when}", "updated": "Aktualisiert {when}",
"search": "{count} Container durchsuchen", "search": "{count} Container durchsuchen",
"selected": "{selectCount} von {totalCount} ausgewählten Containern" "selected": "{selectCount} von {totalCount} ausgewählten Containern",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "Tot" "dead": "Tot"
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "" "label": ""
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "Starten", "label": "Starten",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "Zertifikate" "label": "Zertifikate",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "Vertrauenswürdige Zertifikate", "title": "Vertrauenswürdige Zertifikate",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "Gültig bis {when}" "expires": "Gültig bis {when}",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "Das Zertifikat konnte nicht entfernt werden" "message": "Das Zertifikat konnte nicht entfernt werden"
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+311 -104
View File
@@ -612,15 +612,15 @@
"select": { "select": {
"label": "App auswählen", "label": "App auswählen",
"notFound": "Keine App gefunden", "notFound": "Keine App gefunden",
"search": "", "search": "Nach einer App suchen",
"noResults": "", "noResults": "Keine Ergebnisse",
"action": "", "action": "{app} auswählen",
"title": "" "title": "Wählen Sie eine App, die diesem Board hinzugefügt werden soll"
}, },
"create": { "create": {
"title": "Neue App erstellen", "title": "Neue App erstellen",
"description": "", "description": "Eine neue App erstellen",
"action": "" "action": "App-Erstellung öffnen"
}, },
"add": "App hinzufügen" "add": "App hinzufügen"
} }
@@ -702,6 +702,132 @@
"create": "Verbindung erstellen und testen", "create": "Verbindung erstellen und testen",
"edit": "Verbindung erstellen und speichern" "edit": "Verbindung erstellen und speichern"
}, },
"error": {
"common": {
"cause": {
"title": "Fall mit mehr Details"
}
},
"unknown": {
"title": "Unbekannter Fehler",
"description": "Ein unbekannter Fehler ist aufgetreten, den Fall unten für mehr Details öffnen"
},
"parse": {
"title": "Fehler beim Parsen",
"description": "Die Antwort konnte nicht analysiert werden. Bitte stellen Sie sicher, dass die URL auf die Basis-URL des Dienstes zeigt."
},
"authorization": {
"title": "Autorisierungsfehler",
"description": "Die Anfrage wurde nicht autorisiert. Bitte überprüfen Sie, ob die Anmeldedaten korrekt sind und Sie diese mit mit den entsprechenden Berechtigungen konfiguriert haben."
},
"statusCode": {
"title": "Antwort Fehler",
"description": "Unerwartete {statusCode} ({reason}) Antwort von <url></url>erhalten. Bitte überprüfen Sie, ob die URL auf die Basis-URL der Integration verweist.",
"otherDescription": "Unerwartete {statusCode} Antwort von <url></url>erhalten. Bitte stellen Sie sicher, dass die URL auf die Basis-URL der Integration zeigt.",
"reason": {
"badRequest": "Fehlerhafte Anfrage",
"notFound": "Nicht gefunden",
"tooManyRequests": "Zu viele Anfragen",
"internalServerError": "Interner Serverfehler",
"serviceUnavailable": "Dienst nicht verfügbar",
"gatewayTimeout": "Gateway-Zeitüberschreitung"
}
},
"certificate": {
"title": "Zertifikatfehler",
"description": {
"expired": "Das Zertifikat ist abgelaufen.",
"notYetValid": "Das Zertifikat ist noch nicht gültig.",
"untrusted": "Dem Zertifikat wird nicht vertraut.",
"hostnameMismatch": "Der Hostname des Zertifikats entspricht nicht der URL."
},
"alert": {
"permission": {
"title": "Nicht genügend Berechtigungen",
"message": "Sie sind nicht berechtigt Zertifikate zu vertrauen oder hochzuladen. Bitte kontaktieren Sie Ihren Administrator, um das notwendige Root-Zertifikat hochzuladen."
},
"hostnameMismatch": {
"title": "Hostname stimmt nicht überein",
"message": "Der Hostname im Zertifikat stimmt nicht mit dem Hostnamen überein, mit dem Sie probieren sich zu verbinden. Dies könnte auf ein Sicherheitsrisiko hindeuten, Sie können trotzdem diesem Zertifikat vertrauen."
},
"extract": {
"title": "CA-Zertifikatextraktion fehlgeschlagen",
"message": "Nur selbstsignierte Zertifikate ohne Kette können automatisch abgerufen werden. Falls Sie ein selbst signiertes Zertifikat verwenden, stellen Sie bitte sicher, dass Sie das CA-Zertifikat manuell hochladen. Hier finden Sie Anweisungen, wie man das <docsLink></docsLink> macht."
}
},
"action": {
"retry": {
"label": "Erstellung wiederholen"
},
"trust": {
"label": "Zertifikat vertrauen"
},
"upload": {
"label": "Zertifikat hochladen"
}
},
"hostnameMismatch": {
"confirm": {
"title": "Der Nichtübereinstimmung der Hostnamen zustimmen",
"message": "Sind Sie sicher, dass Sie dem Zertifikat mit einer Nichtübereinstimmung des Hostnamens vertrauen möchten?"
},
"notification": {
"success": {
"title": "Vertrauenswürdige Zertifikate",
"message": "Hostname zu vertrauenswürdiger Zertifikatsliste hinzugefügt"
},
"error": {
"title": "Ein Fehler ist beim vertrauen des Zertifikats aufgetreten",
"message": "Dem Zertifikat mit einer Nichtübereinstimmung des Hostnamens konnte nicht vertraut werden"
}
}
},
"selfSigned": {
"confirm": {
"title": "Selbstsigniertem Zertifikat vertrauen",
"message": "Sind Sie sicher, dass Sie diesem selbst signierten Zertifikat vertrauen möchten?"
},
"notification": {
"success": {
"title": "Vertrauenswürdige Zertifikate",
"message": "Zertifikat zur vertrauenswürdigen Zertifikatsliste hinzugefügt"
},
"error": {
"title": "Ein Fehler ist beim vertrauen des Zertifikats aufgetreten",
"message": "Das Zertifikat konnte nicht zur vertrauenswürdigen Zertifikatsliste hinzugefügt werden"
}
}
},
"details": {
"title": "Details",
"description": "Überprüfen Sie die Zertifikatsinformationen, bevor Sie sich dazu entschließen, ihr zu vertrauen.",
"content": {
"action": "Inhalt anzeigen",
"title": "PEM Zertifikat"
}
}
},
"request": {
"title": "Anfrage Fehler",
"description": {
"connection": {
"hostUnreachable": "Der Server konnte nicht erreicht werden. Dies bedeutet in der Regel, dass der Host offline oder nicht von Ihrem Netzwerk aus erreichbar ist.",
"networkUnreachable": "Das Netzwerk ist nicht erreichbar. Bitte überprüfen Sie Ihre Internetverbindung oder die Netzwerkkonfiguration.",
"refused": "Der Server hat die Verbindung abgelehnt. Er läuft möglicherweise nicht oder lehnt Anfragen auf dem angegebenen Port ab.",
"reset": "Die Verbindung wurde unerwartet vom Server getrennt. Dies kann passieren, wenn der Server instabil ist oder neu gestartet wurde."
},
"dns": {
"notFound": "Die Serveradresse konnte nicht gefunden werden. Bitte überprüfen Sie die URL auf Tippfehler oder ungültige Domainnamen.",
"timeout": "Zeitüberschreitung bei der DNS Anfrage. Dies kann ein temporäres Problem sein – bitte versuchen Sie es in ein paar Augenblicken erneut.",
"noAnswer": "Der DNS-Server hat keine gültige Antwort zurückgegeben. Die Domain existiert vielleicht, hat jedoch keine gültigen Datensätze."
},
"timeout": {
"aborted": "Die Anfrage wurde abgebrochen, bevor sie abgeschlossen werden konnte. Dies könnte auf eine Benutzeraktion oder einen System Timeout zurückzuführen sein.",
"timeout": "Die Anfrage zu bearbeiten hat zu lange gedauert, sie ist damit abgelaufen. Überprüfe dein Netzwerk oder versuche es später erneut."
}
}
}
},
"alertNotice": "Der Speichern Button ist verfügbar, sobald eine erfolgreiche Verbindung hergestellt wurde", "alertNotice": "Der Speichern Button ist verfügbar, sobald eine erfolgreiche Verbindung hergestellt wurde",
"notification": { "notification": {
"success": { "success": {
@@ -769,8 +895,8 @@
"message": "Der Pfad ist vermutlich nicht korrekt" "message": "Der Pfad ist vermutlich nicht korrekt"
}, },
"tooManyRequests": { "tooManyRequests": {
"title": "", "title": "Zu viele Anfragen innerhalb einer bestimmten Zeit",
"message": "" "message": "Es gab zu viele Anfragen. Sie werden wahrscheinlich vom Zielsystem begrenzt oder abgelehnt"
} }
} }
}, },
@@ -878,6 +1004,7 @@
"cancel": "Abbrechen", "cancel": "Abbrechen",
"delete": "Löschen", "delete": "Löschen",
"discard": "Verwerfen", "discard": "Verwerfen",
"close": "Schließen",
"confirm": "Bestätigen", "confirm": "Bestätigen",
"continue": "Fortfahren", "continue": "Fortfahren",
"previous": "Zurück", "previous": "Zurück",
@@ -1093,7 +1220,7 @@
"label": "Integrationen" "label": "Integrationen"
}, },
"title": { "title": {
"label": "" "label": "Titel"
}, },
"customCssClasses": { "customCssClasses": {
"label": "Benutzerdefinierte CSS Klassen" "label": "Benutzerdefinierte CSS Klassen"
@@ -1445,76 +1572,76 @@
} }
}, },
"stockPrice": { "stockPrice": {
"name": "", "name": "Aktienpreis",
"description": "", "description": "Zeigt den aktuellen Aktienkurs einer Firma an",
"option": { "option": {
"stock": { "stock": {
"label": "" "label": "Aktiensymbol"
}, },
"timeRange": { "timeRange": {
"label": "", "label": "Zeitraum",
"option": { "option": {
"1d": { "1d": {
"label": "" "label": "1 Tag"
}, },
"5d": { "5d": {
"label": "" "label": "5 Tage"
}, },
"1mo": { "1mo": {
"label": "" "label": "1 Monat"
}, },
"3mo": { "3mo": {
"label": "" "label": "3 Monate"
}, },
"6mo": { "6mo": {
"label": "" "label": "6 Monate"
}, },
"ytd": { "ytd": {
"label": "" "label": "Bisheriger Jahresverlauf"
}, },
"1y": { "1y": {
"label": "" "label": "1 Jahr"
}, },
"2y": { "2y": {
"label": "" "label": "2 Jahre"
}, },
"5y": { "5y": {
"label": "" "label": "5 Jahre"
}, },
"10y": { "10y": {
"label": "" "label": "10 Jahre"
}, },
"max": { "max": {
"label": "" "label": "Max"
} }
} }
}, },
"timeInterval": { "timeInterval": {
"label": "", "label": "Zeitintervall",
"option": { "option": {
"5m": { "5m": {
"label": "" "label": "5 Minuten"
}, },
"15m": { "15m": {
"label": "" "label": "15 Minuten"
}, },
"30m": { "30m": {
"label": "" "label": "30 Minuten"
}, },
"1h": { "1h": {
"label": "" "label": "1 Stunde"
}, },
"1d": { "1d": {
"label": "" "label": "1 Tag"
}, },
"5d": { "5d": {
"label": "" "label": "5 Tage"
}, },
"1wk": { "1wk": {
"label": "" "label": "1 Woche"
}, },
"1mo": { "1mo": {
"label": "" "label": "1 Monat"
} }
} }
} }
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "Speicher-Info anzeigen" "label": "Speicher-Info anzeigen"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "Dateisystem Info anzeigen" "label": "Dateisystem Info anzeigen"
}, },
"defaultTab": { "defaultTab": {
"label": "Standard Tab" "label": "Standard Tab"
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "Anforderung der Sektionsindikatoren" "label": "Anforderung der Sektionsindikatoren"
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "Stadt / Postleitzahl", "query": "Stadt / Postleitzahl",
@@ -1771,8 +1912,8 @@
"description": "Zeige die aktuellen Streams auf deinen Medienservern an", "description": "Zeige die aktuellen Streams auf deinen Medienservern an",
"option": { "option": {
"showOnlyPlaying": { "showOnlyPlaying": {
"label": "", "label": "Nur aktuelle Wiedergabe anzeigen",
"description": "" "description": "Diese Einstellung zu deaktivieren wird für Plex nicht funktionieren"
} }
}, },
"items": { "items": {
@@ -1805,7 +1946,7 @@
"label": "Torrent Einträge anzeigen die abgeschlossen wurden" "label": "Torrent Einträge anzeigen die abgeschlossen wurden"
}, },
"showCompletedHttp": { "showCompletedHttp": {
"label": "" "label": "Andere Einträge als abgeschlossen anzeigen"
}, },
"activeTorrentThreshold": { "activeTorrentThreshold": {
"label": "Abgeschlossene Torrents unter diesem Schwellenwert ausblenden (in kiB/s)" "label": "Abgeschlossene Torrents unter diesem Schwellenwert ausblenden (in kiB/s)"
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "Filter zur Berechnung des Verhältnisses verwenden" "label": "Filter zur Berechnung des Verhältnisses verwenden"
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -1950,7 +2095,7 @@
"approved": "Bestätigt", "approved": "Bestätigt",
"declined": "Abgelehnt", "declined": "Abgelehnt",
"failed": "Fehlgeschlagen", "failed": "Fehlgeschlagen",
"completed": "" "completed": "Abgeschlossen"
}, },
"toBeDetermined": "Noch Festzulegen" "toBeDetermined": "Noch Festzulegen"
}, },
@@ -2054,94 +2199,94 @@
} }
}, },
"releases": { "releases": {
"name": "", "name": "Veröffentlichungen",
"description": "", "description": "Zeigt eine Liste der aktuellen Version der angegebenen Repositories mit der angegebenen Version regex an.",
"option": { "option": {
"newReleaseWithin": { "newReleaseWithin": {
"label": "", "label": "Neue Version innerhalb",
"description": "" "description": "Anwendungsbeispiel: 1w (1 Woche), 10M (10 Monate). Akzeptierte Einheiten h (Stunden), d (Tage), w (Wochen), M (Monate), y (Jahre). Leer lassen für keine Hervorhebung neuer Releases."
}, },
"staleReleaseWithin": { "staleReleaseWithin": {
"label": "", "label": "Veraltete Version innerhalb",
"description": "" "description": "Anwendungsbeispiel: 1w (1 Woche), 10M (10 Monate). Akzeptierte Einheiten h (Stunden), d (Tage), w (Wochen), M (Monate), y (Jahre). Leer lassen für keine Hervorhebung von veralteten Releases."
}, },
"showOnlyHighlighted": { "showOnlyHighlighted": {
"label": "", "label": "Nur markierte anzeigen",
"description": "" "description": "Nur neue oder veraltete Versionen anzeigen. Wie oben beschrieben."
}, },
"showDetails": { "showDetails": {
"label": "" "label": "Details anzeigen"
}, },
"topReleases": { "topReleases": {
"label": "", "label": "Top Releases",
"description": "" "description": "Die maximale Anzahl der neuesten Versionen, die angezeigt werden sollen. Null bedeutet kein Limit."
}, },
"repositories": { "repositories": {
"label": "", "label": "Repositories",
"addRRepository": { "addRRepository": {
"label": "" "label": "Repository hinzufügen"
}, },
"provider": { "provider": {
"label": "" "label": "Anbieter"
}, },
"identifier": { "identifier": {
"label": "", "label": "Identifier",
"placeholder": "" "placeholder": "Name oder Eigentümer/Name"
}, },
"name": { "name": {
"label": "" "label": "Name"
}, },
"versionFilter": { "versionFilter": {
"label": "", "label": "Versionsfilter",
"prefix": { "prefix": {
"label": "" "label": "Präfix"
}, },
"precision": { "precision": {
"label": "", "label": "Präzision",
"options": { "options": {
"none": "" "none": "Keine"
} }
}, },
"suffix": { "suffix": {
"label": "" "label": "Suffix"
}, },
"regex": { "regex": {
"label": "" "label": "Regulärer Ausdruck"
} }
}, },
"edit": { "edit": {
"label": "" "label": "Bearbeiten"
}, },
"editForm": { "editForm": {
"title": "", "title": "Repository bearbeiten",
"cancel": { "cancel": {
"label": "" "label": "Abbrechen"
}, },
"confirm": { "confirm": {
"label": "" "label": "Bestätigen"
} }
}, },
"example": { "example": {
"label": "" "label": "Beispiel"
}, },
"invalid": "" "invalid": "Ungültige Repository Definition, bitte überprüfen Sie die Werte"
} }
}, },
"not-found": "", "not-found": "Nicht gefunden",
"pre-release": "", "pre-release": "Vorveröffentlichung",
"archived": "", "archived": "Archiviert",
"forked": "", "forked": "Forked",
"starsCount": "", "starsCount": "Sterne",
"forksCount": "", "forksCount": "Ableger",
"issuesCount": "", "issuesCount": "Offene Tickets",
"openProjectPage": "", "openProjectPage": "Projektseite öffnen",
"openReleasePage": "", "openReleasePage": "Release Seite öffnen",
"releaseDescription": "", "releaseDescription": "Release Beschreibung",
"created": "", "created": "Erstellt",
"error": { "error": {
"label": "", "label": "Fehler",
"options": { "options": {
"noMatchingVersion": "" "noMatchingVersion": "Keine passende Version gefunden"
} }
} }
}, },
@@ -2149,56 +2294,56 @@
"option": {}, "option": {},
"card": { "card": {
"vpn": { "vpn": {
"countConnected": "" "countConnected": "{count} verbunden"
} }
}, },
"error": { "error": {
"integrationsDisconnected": "", "integrationsDisconnected": "Keine Daten verfügbar, alle Integrationen getrennt",
"unknownContentOption": "" "unknownContentOption": "Unbekannte Inhaltsoption für das Widget der Netzwerk Controller Zusammenfassung: "
}, },
"name": "", "name": "Netzwerk Controller Zusammenfassung",
"description": "" "description": "Zeigt die Zusammenfassung eines Netzwerk Controller (wie UniFi-Controller) an"
}, },
"networkControllerStatus": { "networkControllerStatus": {
"card": { "card": {
"variants": { "variants": {
"wired": { "wired": {
"name": "" "name": "Kabel"
}, },
"wifi": { "wifi": {
"name": "" "name": "WLAN"
} }
}, },
"users": { "users": {
"label": "" "label": "Benutzer"
}, },
"guests": { "guests": {
"label": "" "label": "Gäste"
} }
}, },
"option": { "option": {
"content": { "content": {
"option": { "option": {
"wifi": { "wifi": {
"label": "" "label": "WLAN"
}, },
"wired": { "wired": {
"label": "" "label": "Kabel"
} }
}, },
"label": "" "label": "Widget Inhalt"
} }
}, },
"error": { "error": {
"integrationsDisconnected": "", "integrationsDisconnected": "Keine Daten verfügbar, alle Integrationen getrennt",
"unknownContentOption": "" "unknownContentOption": "Unbekannte Inhaltsoption für das Netzwerkstatus Widget: "
}, },
"name": "", "name": "Netzwerkstatus",
"description": "" "description": "Angeschlossene Geräte in einem Netzwerk anzeigen"
}, },
"networkController": { "networkController": {
"error": { "error": {
"internalServerError": "" "internalServerError": "Fehler beim Abrufen der Netzwerk Controller Zusammenfassung"
} }
} }
}, },
@@ -2321,10 +2466,10 @@
}, },
"backgroundImageUrl": { "backgroundImageUrl": {
"label": "URL des Hintergrundbildes", "label": "URL des Hintergrundbildes",
"placeholder": "", "placeholder": "Tippen, um nach lokale Bilder zu suchen",
"group": { "group": {
"your": "", "your": "Ihre Bilder",
"other": "" "other": "Andere Bilder"
} }
}, },
"backgroundImageAttachment": { "backgroundImageAttachment": {
@@ -2963,6 +3108,9 @@
"label": "Medien Transkodierung" "label": "Medien Transkodierung"
}, },
"networkController": { "networkController": {
"label": "Netzwerk Controller"
},
"dockerContainers": {
"label": "" "label": ""
} }
} }
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "Aktualisiert {when}", "updated": "Aktualisiert {when}",
"search": "{count} Container durchsuchen", "search": "{count} Container durchsuchen",
"selected": "{selectCount} von {totalCount} ausgewählten Containern" "selected": "{selectCount} von {totalCount} ausgewählten Containern",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "Tot" "dead": "Tot"
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "Image" "label": "Image"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "Starten", "label": "Starten",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "Logs" "label": "Logs"
}, },
"certificates": { "certificates": {
"label": "Zertifikate" "label": "Zertifikate",
"hostnames": {
"label": "Hostnamen"
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": "Hostname"
},
"subject": {
"label": "Thema"
},
"issuer": {
"label": "Ersteller"
},
"validFrom": {
"label": "Gültig ab"
},
"validTo": {
"label": "Gültig bis"
},
"serialNumber": {
"label": "Seriennummer"
},
"fingerprint": {
"label": "Fingerabdruck"
}
},
"page": { "page": {
"list": { "list": {
"title": "Vertrauenswürdige Zertifikate", "title": "Vertrauenswürdige Zertifikate",
@@ -3902,10 +4086,19 @@
"title": "Es gibt noch keine Zertifikate" "title": "Es gibt noch keine Zertifikate"
}, },
"invalid": { "invalid": {
"title": "", "title": "Ungültiges Zertifikat",
"description": "" "description": "Fehler beim Analysieren des Zertifikats"
}, },
"expires": "Gültig bis {when}" "expires": "Gültig bis {when}",
"toHostnames": "Vertrauenswürdige Hostnamen"
},
"hostnames": {
"title": "Hostnamen der vertrauten Zertifikate",
"description": "Einige Zertifikate erlauben es der spezifischen Domäne von Homarr nicht, sie anzufordern. Um diese Einschränkungen zu umgehen werden alle vertrauenswürdigen Hostnamen mit ihrem Zertifikats Fingerabdruck verwendet.",
"noResults": {
"title": "Noch keine Hostnamen vorhanden"
},
"toCertificates": "Zertifikate"
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "Das Zertifikat konnte nicht entfernt werden" "message": "Das Zertifikat konnte nicht entfernt werden"
} }
} }
},
"removeHostname": {
"label": "Vertrauenswürdigen Hostnamen entfernen",
"confirm": "Sind Sie sicher, dass Sie diesen vertrauenswürdigen Hostnamen entfernen wollen? Dies kann dazu führen, dass einige Integrationen nicht mehr funktionieren.",
"notification": {
"success": {
"title": "Hostname entfernt",
"message": "Der Hostname wurde erfolgreich entfernt"
},
"error": {
"title": "Hostname nicht entfernt",
"message": "Der Hostname konnte nicht entfernt werden"
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "", "create": "",
"edit": "" "edit": ""
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "", "alertNotice": "",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Ακύρωση", "cancel": "Ακύρωση",
"delete": "Διαγραφή", "delete": "Διαγραφή",
"discard": "", "discard": "",
"close": "",
"confirm": "Επιβεβαίωση", "confirm": "Επιβεβαίωση",
"continue": "", "continue": "",
"previous": "Προηγούμενο", "previous": "Προηγούμενο",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "Εμφάνιση Πληροφοριών Μνήμης" "label": "Εμφάνιση Πληροφοριών Μνήμης"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "Εμφάνιση Πληροφοριών Συστήματος Αρχείων" "label": "Εμφάνιση Πληροφοριών Συστήματος Αρχείων"
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "Εικόνα" "label": "Εικόνα"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "Έναρξη", "label": "Έναρξη",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "Test the connection and create integration", "create": "Test the connection and create integration",
"edit": "Test the connection and save" "edit": "Test the connection and save"
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "The save button is enabled once the connection is successfully established", "alertNotice": "The save button is enabled once the connection is successfully established",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Cancel", "cancel": "Cancel",
"delete": "Delete", "delete": "Delete",
"discard": "Discard", "discard": "Discard",
"close": "",
"confirm": "Confirm", "confirm": "Confirm",
"continue": "Continue", "continue": "Continue",
"previous": "Previous", "previous": "Previous",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "" "label": ""
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "" "label": ""
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "" "label": ""
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "", "label": "",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+33 -2
View File
@@ -1757,12 +1757,18 @@
"memory": { "memory": {
"label": "Show Memory Info" "label": "Show Memory Info"
}, },
"showUptime": {
"label": "Show Uptime"
},
"fileSystem": { "fileSystem": {
"label": "Show Filesystem Info" "label": "Show Filesystem Info"
}, },
"defaultTab": { "defaultTab": {
"label": "Default tab" "label": "Default tab"
}, },
"visibleClusterSections": {
"label": "Visible cluster sections"
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "Section indicator requirement" "label": "Section indicator requirement"
} }
@@ -1832,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "Docker stats",
"description": "Stats of your containers (This widget can only be added with administrator privileges)",
"option": {},
"error": {
"internalServerError": "Failed to fetch containers stats"
}
},
"common": { "common": {
"location": { "location": {
"query": "City / Postal code", "query": "City / Postal code",
@@ -1945,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "Use filter to calculate Ratio" "label": "Use filter to calculate Ratio"
},
"limitPerIntegration": {
"label": "Limit items per integration",
"description": "This will limit the number of items shown per integration, not globally"
} }
}, },
"errors": { "errors": {
@@ -3091,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "Network Controller" "label": "Network Controller"
},
"dockerContainers": {
"label": "Docker containers"
} }
} }
}, },
@@ -3154,8 +3175,9 @@
"title": "Containers", "title": "Containers",
"table": { "table": {
"updated": "Updated {when}", "updated": "Updated {when}",
"search": "Search {count} containers", "search": "Seach {count} containers",
"selected": "{selectCount} of {totalCount} containers selected" "selected": "{selectCount} of {totalCount} containers selected",
"footer": "Total {count} containers"
}, },
"field": { "field": {
"name": { "name": {
@@ -3173,6 +3195,14 @@
"dead": "Dead" "dead": "Dead"
} }
}, },
"stats": {
"cpu": {
"label": "CPU"
},
"memory": {
"label": "Memory"
}
},
"containerImage": { "containerImage": {
"label": "Image" "label": "Image"
}, },
@@ -3181,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "Actions",
"start": { "start": {
"label": "Start", "label": "Start",
"notification": { "notification": {
+214 -7
View File
@@ -3,7 +3,7 @@
"step": { "step": {
"start": { "start": {
"title": "Bienvenido a Homarr", "title": "Bienvenido a Homarr",
"subtitle": "Comencemos con la configuración de tu instancia de Homar.", "subtitle": "Comencemos con la configuración de tu instancia de Homarr.",
"description": "Para empezar, por favor, seleccione cómo desea configurar su instancia de Homarr.", "description": "Para empezar, por favor, seleccione cómo desea configurar su instancia de Homarr.",
"action": { "action": {
"scratch": "Empezar de cero", "scratch": "Empezar de cero",
@@ -35,7 +35,7 @@
} }
}, },
"summary": { "summary": {
"title": "Importar resumen", "title": "Resumen de importación",
"description": "", "description": "",
"action": { "action": {
"import": "Confirmar la importación y continuar" "import": "Confirmar la importación y continuar"
@@ -160,7 +160,7 @@
} }
}, },
"error": { "error": {
"usernameTaken": "Nombre de usuario ya está ocupado" "usernameTaken": ""
}, },
"action": { "action": {
"login": { "login": {
@@ -172,7 +172,7 @@
"message": "" "message": ""
}, },
"error": { "error": {
"title": "", "title": "Inicio de sesión fallido",
"message": "" "message": ""
} }
}, },
@@ -702,6 +702,132 @@
"create": "", "create": "",
"edit": "" "edit": ""
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "", "alertNotice": "",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Cancelar", "cancel": "Cancelar",
"delete": "Eliminar", "delete": "Eliminar",
"discard": "", "discard": "",
"close": "",
"confirm": "Confirmar", "confirm": "Confirmar",
"continue": "", "continue": "",
"previous": "Anterior", "previous": "Anterior",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "Mostrar información de la memoria" "label": "Mostrar información de la memoria"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "Mostrar información del sistema de archivos" "label": "Mostrar información del sistema de archivos"
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "Imagen" "label": "Imagen"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "Iniciar", "label": "Iniciar",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "", "create": "",
"edit": "" "edit": ""
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "", "alertNotice": "",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "", "cancel": "",
"delete": "", "delete": "",
"discard": "", "discard": "",
"close": "",
"confirm": "", "confirm": "",
"continue": "", "continue": "",
"previous": "", "previous": "",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "" "label": ""
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "" "label": ""
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "" "label": ""
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "", "label": "",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "Tester la connexion et créer", "create": "Tester la connexion et créer",
"edit": "Tester la connexion et enregistrer" "edit": "Tester la connexion et enregistrer"
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "Le bouton Enregistrer est activé une fois qu'une connexion est établie avec succès", "alertNotice": "Le bouton Enregistrer est activé une fois qu'une connexion est établie avec succès",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Annuler", "cancel": "Annuler",
"delete": "Supprimer", "delete": "Supprimer",
"discard": "Abandonner", "discard": "Abandonner",
"close": "",
"confirm": "Confirmer", "confirm": "Confirmer",
"continue": "Continuer", "continue": "Continuer",
"previous": "Précédent", "previous": "Précédent",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "Afficher les infos de la mémoire" "label": "Afficher les infos de la mémoire"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "Afficher les infos sur le système de fichiers" "label": "Afficher les infos sur le système de fichiers"
}, },
"defaultTab": { "defaultTab": {
"label": "Onglet par défaut" "label": "Onglet par défaut"
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "Exigence de l'indicateur de section" "label": "Exigence de l'indicateur de section"
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "Ville / Code Postal", "query": "Ville / Code Postal",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "Utiliser le filtre pour calculer le ratio" "label": "Utiliser le filtre pour calculer le ratio"
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "Mis à jour {when}", "updated": "Mis à jour {when}",
"search": "Rechercher dans {count} conteneurs", "search": "Rechercher dans {count} conteneurs",
"selected": "{selectCount} sur {totalCount} conteneurs sélectionnés" "selected": "{selectCount} sur {totalCount} conteneurs sélectionnés",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "Mort" "dead": "Mort"
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "Image" "label": "Image"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "Début", "label": "Début",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "Journaux" "label": "Journaux"
}, },
"certificates": { "certificates": {
"label": "Certificats" "label": "Certificats",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "Certificats de confiance", "title": "Certificats de confiance",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "Expire le {when}" "expires": "Expire le {when}",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "Le certificat n'a pas pu être supprimé" "message": "Le certificat n'a pas pu être supprimé"
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+217 -10
View File
@@ -702,6 +702,132 @@
"create": "בדוק חיבור וצור", "create": "בדוק חיבור וצור",
"edit": "בדוק את החיבור ושמור" "edit": "בדוק את החיבור ושמור"
}, },
"error": {
"common": {
"cause": {
"title": "סיבה עם פרטים נוספים"
}
},
"unknown": {
"title": "שגיאה לא ידועה",
"description": "אירעה שגיאה לא ידועה, פתח את הסיבה למטה כדי לראות פרטים נוספים"
},
"parse": {
"title": "שגיאת ניתוח",
"description": "לא ניתן היה לנתח את התגובה. אנא ודא שכתובת האתר מפנה לכתובת האתר הבסיסית של השירות."
},
"authorization": {
"title": "שגיאת הרשאה",
"description": "הבקשה לא אושרה. אנא ודא שהאישורים נכונים ושהוגדרו לך הרשאות מספיקות."
},
"statusCode": {
"title": "שגיאת תגובה",
"description": "התקבלה תגובה בלתי צפויה של {statusCode} ({reason}) מ-<url></url>. אנא ודא שכתובת האתר מפנה לכתובת האתר הבסיסית של האינטגרציה.",
"otherDescription": "התקבלה תגובה בלתי צפויה של {statusCode} מ-<url></url>. אנא ודא שכתובת האתר מפנה לכתובת האתר הבסיסית של האינטגרציה.",
"reason": {
"badRequest": "בקשה שגויה",
"notFound": "לא נמצא",
"tooManyRequests": "בקשות רבות מדי",
"internalServerError": "שגיאת שרת פנימית",
"serviceUnavailable": "השירות אינו זמין",
"gatewayTimeout": "פסק זמן של השער"
}
},
"certificate": {
"title": "שגיאת תעודה",
"description": {
"expired": "פג תוקפה של תעודה זו.",
"notYetValid": "התעודה עדיין אינה בתוקף.",
"untrusted": "התעודה אינה מהימנה.",
"hostnameMismatch": "שם המארח של האישור אינו תואם לכתובת ה-URL."
},
"alert": {
"permission": {
"title": "אין מספיק הרשאות",
"message": "אינך רשאי לתת אמון באישורים או להעלות אותם. אנא צור קשר עם מנהל המערכת שלך כדי להעלות את אישור הבסיס הדרוש."
},
"hostnameMismatch": {
"title": "שם השרת לא תואם",
"message": "שם המארח בתעודה אינו תואם לשם המארח שאליו אתה מתחבר. זה יכול להצביע על סיכון אבטחה, אך עדיין תוכל לבחור לתת אמון בתעודה זו."
},
"extract": {
"title": "חילוץ תעודת CA נכשל",
"message": "ניתן לאחזר באופן אוטומטי רק אישורים חתומים עצמית ללא שרשרת. אם אתם משתמשים באישור חתום עצמית, אנא ודאו שאתם מעלים את אישור רשות האישור באופן ידני. תוכלו למצוא הוראות כיצד לעשות זאת <docsLink></docsLink>."
}
},
"action": {
"retry": {
"label": "נסה ליצור שוב"
},
"trust": {
"label": "תעודה מהימנה"
},
"upload": {
"label": "העלאת תעודת אבטחה"
}
},
"hostnameMismatch": {
"confirm": {
"title": "אי התאמה בשם המארח",
"message": "האם אתה בטוח שאתה רוצה לסמוך על האישור עם אי התאמה בשם המארח?"
},
"notification": {
"success": {
"title": "תעודה מהימנה",
"message": "נוסף שם מארח לרשימת האישורים המהימנים"
},
"error": {
"title": "נכשל בהוספת תעודת אבטחה",
"message": "לא ניתן היה לסמוך על האישור עם אי-התאמה בשם המארח"
}
}
},
"selfSigned": {
"confirm": {
"title": "תעודת אמון חתומה עצמית",
"message": "האם אתה בטוח שאתה רוצה לסמוך על אישור חתום עצמי זה?"
},
"notification": {
"success": {
"title": "תעודה מהימנה",
"message": "נוסף שם מארח לרשימת האישורים המהימנים"
},
"error": {
"title": "נכשל בהוספת תעודת אבטחה",
"message": "נכשל בהוספת האישור לרשימת האישורים המהימנים"
}
}
},
"details": {
"title": "פרטים",
"description": "בדוק את פרטי האישור לפני שתחליט לסמוך עליו.",
"content": {
"action": "הצג תוכן",
"title": "תעודת PEM"
}
}
},
"request": {
"title": "שגיאת בקשה",
"description": {
"connection": {
"hostUnreachable": "לא ניתן היה להגיע לשרת. משמעות הדבר בדרך כלל היא שהמארח לא מקוון או שאינו ניתן להשגה מהרשת שלך.",
"networkUnreachable": "הרשת אינה נגישה. אנא בדוק את חיבור האינטרנט או את תצורת הרשת שלך.",
"refused": "השרת דחה את החיבור. ייתכן שהוא אינו פועל או דוחה בקשות בפורט שצוין.",
"reset": "החיבור נסגר באופן בלתי צפוי על ידי השרת. זה יכול לקרות אם השרת אינו יציב או שהופעל מחדש."
},
"dns": {
"notFound": "לא ניתן היה למצוא את כתובת השרת. אנא בדוק את כתובת ה-URL עבור שגיאות הקלדה או שמות דומיין לא חוקיים.",
"timeout": "בדיקת DNS הסתיימה. ייתכן שמדובר בבעיה זמנית - אנא נסה שוב בעוד מספר רגעים.",
"noAnswer": "שרת ה-DNS לא החזיר תגובה תקפה. ייתכן שהדומיין קיים אך אין לו רשומות תקפות."
},
"timeout": {
"aborted": "הבקשה בוטלה לפני שהספיקה להשלים אותה. ייתכן שהדבר נובע מפעולת משתמש או מפסק זמן של המערכת.",
"timeout": "הבקשה ארכה זמן רב מדי להשלמה ופג תוקפו. בדוק את הרשת שלך או נסה שוב מאוחר יותר."
}
}
}
},
"alertNotice": "הלחצן שמור מופעל לאחר יצירת חיבור מוצלח", "alertNotice": "הלחצן שמור מופעל לאחר יצירת חיבור מוצלח",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "בטל", "cancel": "בטל",
"delete": "מחיקה", "delete": "מחיקה",
"discard": "ביטול", "discard": "ביטול",
"close": "סגור",
"confirm": "לאשר", "confirm": "לאשר",
"continue": "המשך", "continue": "המשך",
"previous": "הקודם", "previous": "הקודם",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "הצג מידע זיכרון" "label": "הצג מידע זיכרון"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "הצג מידע על מערכת הקבצים" "label": "הצג מידע על מערכת הקבצים"
}, },
"defaultTab": { "defaultTab": {
"label": "כרטיסיית ברירת מחדל" "label": "כרטיסיית ברירת מחדל"
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "דרישת מציין מקטע" "label": "דרישת מציין מקטע"
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "סטטיסטיקות דוקר",
"description": "סטטיסטיקות של המכולות שלך (ניתן להוסיף ווידג'ט זה רק עם הרשאות מנהל)",
"option": {},
"error": {
"internalServerError": "נכשל באחזור סטטיסטיקות המכולות"
}
},
"common": { "common": {
"location": { "location": {
"query": "עיר / מיקוד", "query": "עיר / מיקוד",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "השתמש במסנן כדי לחשב יחס" "label": "השתמש במסנן כדי לחשב יחס"
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2059,11 +2204,11 @@
"option": { "option": {
"newReleaseWithin": { "newReleaseWithin": {
"label": "מהדורה חדשה בתוך", "label": "מהדורה חדשה בתוך",
"description": "" "description": "דוגמת שימוש: שבוע אחד (1), חודש אחד (10 חודשים). סוגי יחידות מקובלים: h (שעות), d (ימים), w (שבועות), M (חודשים), y (שנים). השאר ריק כדי לא להדגיש מהדורות חדשות."
}, },
"staleReleaseWithin": { "staleReleaseWithin": {
"label": "מהדורה חדשה בתוך", "label": "מהדורה חדשה בתוך",
"description": "" "description": "דוגמת שימוש: 1w (שבוע אחד), 10M (10 חודשים). סוגי יחידות מקובלים h (שעות), d (ימים), w (שבועות), M (חודשים), y (שנים). השאר ריק כדי לא להדגיש גרסאות ישנות."
}, },
"showOnlyHighlighted": { "showOnlyHighlighted": {
"label": "הצג רק את המודגשים", "label": "הצג רק את המודגשים",
@@ -2073,8 +2218,8 @@
"label": "הצג פרטים" "label": "הצג פרטים"
}, },
"topReleases": { "topReleases": {
"label": "", "label": "מהדורות מובילות",
"description": "" "description": "המספר המרבי של מהדורות אחרונות להצגה. אפס פירושו שאין הגבלה."
}, },
"repositories": { "repositories": {
"label": "מאגרים", "label": "מאגרים",
@@ -2089,7 +2234,7 @@
"placeholder": "שם או בעלים/שם" "placeholder": "שם או בעלים/שם"
}, },
"name": { "name": {
"label": "" "label": "שם"
}, },
"versionFilter": { "versionFilter": {
"label": "מסנן גירסאות", "label": "מסנן גירסאות",
@@ -2139,9 +2284,9 @@
"releaseDescription": "תיאור הגרסה", "releaseDescription": "תיאור הגרסה",
"created": "נוצר", "created": "נוצר",
"error": { "error": {
"label": "", "label": "שגיאה",
"options": { "options": {
"noMatchingVersion": "" "noMatchingVersion": "לא נמצאה גרסה תואמת"
} }
} }
}, },
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "בקר רשת" "label": "בקר רשת"
},
"dockerContainers": {
"label": "מכולות דוקר"
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "עודכן ב- {when}", "updated": "עודכן ב- {when}",
"search": "חפש {count} קונטיינרים", "search": "חפש {count} קונטיינרים",
"selected": "{selectCount} מ- {totalCount} קונטיינרים נבחרו" "selected": "{selectCount} מ- {totalCount} קונטיינרים נבחרו",
"footer": "סה״כ {count} קונטיינרים"
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "מת" "dead": "מת"
} }
}, },
"stats": {
"cpu": {
"label": "מעבד"
},
"memory": {
"label": "זיכרון"
}
},
"containerImage": { "containerImage": {
"label": "קובץ תמונה" "label": "קובץ תמונה"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "פעולות",
"start": { "start": {
"label": "התחל", "label": "התחל",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "קבצי לוג" "label": "קבצי לוג"
}, },
"certificates": { "certificates": {
"label": "אישורי אבטחה" "label": "אישורי אבטחה",
"hostnames": {
"label": "שמות מארחים"
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": "שם מארח"
},
"subject": {
"label": "נושא"
},
"issuer": {
"label": "מנפיק"
},
"validFrom": {
"label": "בתוקף מ: "
},
"validTo": {
"label": "בתוקף מ: "
},
"serialNumber": {
"label": "מספר סידורי"
},
"fingerprint": {
"label": "טביעת אצבע"
}
},
"page": { "page": {
"list": { "list": {
"title": "תעודות מהימנות", "title": "תעודות מהימנות",
@@ -3905,7 +4089,16 @@
"title": "אישור לא חוקי", "title": "אישור לא חוקי",
"description": "נכשל בהוספת תעודת אבטחה" "description": "נכשל בהוספת תעודת אבטחה"
}, },
"expires": "פג ב- {when}" "expires": "פג ב- {when}",
"toHostnames": "שמות מארחים מאושרים"
},
"hostnames": {
"title": "שמות מארחים של תעודות מהימנות",
"description": "חלק מהאישורים אינם מאפשרים לדומיין הספציפי בו Homarr משתמש לבקש אותם, מסיבה זו כל שמות המארח המהימנים עם טביעות האצבע של האישור שלהם משמשים כדי לעקוף את ההגבלות הללו.",
"noResults": {
"title": "אין עדיין שמות מארחים"
},
"toCertificates": "אישורי אבטחה"
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "לא היה ניתן להסיר את תעודת האבטחה" "message": "לא היה ניתן להסיר את תעודת האבטחה"
} }
} }
},
"removeHostname": {
"label": "הסר שם מארח מהימן",
"confirm": "האם אתה בטוח שברצונך להסיר את שם המארח המהימן הזה? זה עלול לגרום לחלק מהאינטגרציות להפסיק לפעול.",
"notification": {
"success": {
"title": "שם המארח הוסר",
"message": "שם המארח הוסר בהצלחה"
},
"error": {
"title": "שם המארח לא הוסר",
"message": "לא היה ניתן להסיר את שם המארח"
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "", "create": "",
"edit": "" "edit": ""
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "", "alertNotice": "",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Otkaži", "cancel": "Otkaži",
"delete": "Obriši", "delete": "Obriši",
"discard": "", "discard": "",
"close": "",
"confirm": "Potvrdi", "confirm": "Potvrdi",
"continue": "", "continue": "",
"previous": "Prethodno", "previous": "Prethodno",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "" "label": ""
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "" "label": ""
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "Slika" "label": "Slika"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "Pokreni", "label": "Pokreni",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "Tesztelje a kapcsolatot és hozzon létre", "create": "Tesztelje a kapcsolatot és hozzon létre",
"edit": "Tesztelje a kapcsolatot és mentsen" "edit": "Tesztelje a kapcsolatot és mentsen"
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "A Mentés gomb a sikeres kapcsolat létrehozása után aktiválódik", "alertNotice": "A Mentés gomb a sikeres kapcsolat létrehozása után aktiválódik",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Mégse", "cancel": "Mégse",
"delete": "Törlés", "delete": "Törlés",
"discard": "Elvetés", "discard": "Elvetés",
"close": "",
"confirm": "Megerősít", "confirm": "Megerősít",
"continue": "Folytatás", "continue": "Folytatás",
"previous": "Előző", "previous": "Előző",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "Memóriainformációk megjelenítése" "label": "Memóriainformációk megjelenítése"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "Fájlrendszer-információk megjelenítése" "label": "Fájlrendszer-információk megjelenítése"
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "Kép" "label": "Kép"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "Indítás", "label": "Indítás",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "Prova la connessione e crea", "create": "Prova la connessione e crea",
"edit": "Prova la connessione e salva" "edit": "Prova la connessione e salva"
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "Il pulsante Salva è abilitato una volta stabilita una connessione con successo", "alertNotice": "Il pulsante Salva è abilitato una volta stabilita una connessione con successo",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Annulla", "cancel": "Annulla",
"delete": "Elimina", "delete": "Elimina",
"discard": "", "discard": "",
"close": "",
"confirm": "Conferma", "confirm": "Conferma",
"continue": "", "continue": "",
"previous": "Precedente", "previous": "Precedente",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "Mostra Informazioni Memoria" "label": "Mostra Informazioni Memoria"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "Mostra Informazioni Filesystem" "label": "Mostra Informazioni Filesystem"
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "Immagine" "label": "Immagine"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "Avvia", "label": "Avvia",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "", "create": "",
"edit": "" "edit": ""
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "", "alertNotice": "",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "キャンセル", "cancel": "キャンセル",
"delete": "削除", "delete": "削除",
"discard": "", "discard": "",
"close": "",
"confirm": "確認", "confirm": "確認",
"continue": "次へ", "continue": "次へ",
"previous": "前へ", "previous": "前へ",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "メモリー情報を表示" "label": "メモリー情報を表示"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "ファイルシステム情報を表示" "label": "ファイルシステム情報を表示"
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "画像" "label": "画像"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "開始", "label": "開始",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "", "create": "",
"edit": "" "edit": ""
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "", "alertNotice": "",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "취소", "cancel": "취소",
"delete": "삭제", "delete": "삭제",
"discard": "", "discard": "",
"close": "",
"confirm": "확인", "confirm": "확인",
"continue": "", "continue": "",
"previous": "이전", "previous": "이전",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "" "label": ""
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "" "label": ""
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "이미지" "label": "이미지"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "시작", "label": "시작",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "", "create": "",
"edit": "" "edit": ""
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "", "alertNotice": "",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Atšaukti", "cancel": "Atšaukti",
"delete": "", "delete": "",
"discard": "", "discard": "",
"close": "",
"confirm": "", "confirm": "",
"continue": "", "continue": "",
"previous": "", "previous": "",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "" "label": ""
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "" "label": ""
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "Nuotrauka" "label": "Nuotrauka"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "Paleisti", "label": "Paleisti",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
+210 -3
View File
@@ -702,6 +702,132 @@
"create": "", "create": "",
"edit": "" "edit": ""
}, },
"error": {
"common": {
"cause": {
"title": ""
}
},
"unknown": {
"title": "",
"description": ""
},
"parse": {
"title": "",
"description": ""
},
"authorization": {
"title": "",
"description": ""
},
"statusCode": {
"title": "",
"description": "",
"otherDescription": "",
"reason": {
"badRequest": "",
"notFound": "",
"tooManyRequests": "",
"internalServerError": "",
"serviceUnavailable": "",
"gatewayTimeout": ""
}
},
"certificate": {
"title": "",
"description": {
"expired": "",
"notYetValid": "",
"untrusted": "",
"hostnameMismatch": ""
},
"alert": {
"permission": {
"title": "",
"message": ""
},
"hostnameMismatch": {
"title": "",
"message": ""
},
"extract": {
"title": "",
"message": ""
}
},
"action": {
"retry": {
"label": ""
},
"trust": {
"label": ""
},
"upload": {
"label": ""
}
},
"hostnameMismatch": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"selfSigned": {
"confirm": {
"title": "",
"message": ""
},
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
},
"details": {
"title": "",
"description": "",
"content": {
"action": "",
"title": ""
}
}
},
"request": {
"title": "",
"description": {
"connection": {
"hostUnreachable": "",
"networkUnreachable": "",
"refused": "",
"reset": ""
},
"dns": {
"notFound": "",
"timeout": "",
"noAnswer": ""
},
"timeout": {
"aborted": "",
"timeout": ""
}
}
}
},
"alertNotice": "", "alertNotice": "",
"notification": { "notification": {
"success": { "success": {
@@ -878,6 +1004,7 @@
"cancel": "Atcelt", "cancel": "Atcelt",
"delete": "Dzēst", "delete": "Dzēst",
"discard": "", "discard": "",
"close": "",
"confirm": "Apstipriniet", "confirm": "Apstipriniet",
"continue": "", "continue": "",
"previous": "Iepriekšējais", "previous": "Iepriekšējais",
@@ -1630,12 +1757,18 @@
"memory": { "memory": {
"label": "Rādīt atmiņas informāciju" "label": "Rādīt atmiņas informāciju"
}, },
"showUptime": {
"label": ""
},
"fileSystem": { "fileSystem": {
"label": "Rādīt failu sistēmas informāciju" "label": "Rādīt failu sistēmas informāciju"
}, },
"defaultTab": { "defaultTab": {
"label": "" "label": ""
}, },
"visibleClusterSections": {
"label": ""
},
"sectionIndicatorRequirement": { "sectionIndicatorRequirement": {
"label": "" "label": ""
} }
@@ -1705,6 +1838,14 @@
} }
} }
}, },
"dockerContainers": {
"name": "",
"description": "",
"option": {},
"error": {
"internalServerError": ""
}
},
"common": { "common": {
"location": { "location": {
"query": "", "query": "",
@@ -1818,6 +1959,10 @@
}, },
"applyFilterToRatio": { "applyFilterToRatio": {
"label": "" "label": ""
},
"limitPerIntegration": {
"label": "",
"description": ""
} }
}, },
"errors": { "errors": {
@@ -2964,6 +3109,9 @@
}, },
"networkController": { "networkController": {
"label": "" "label": ""
},
"dockerContainers": {
"label": ""
} }
} }
}, },
@@ -3028,7 +3176,8 @@
"table": { "table": {
"updated": "", "updated": "",
"search": "", "search": "",
"selected": "" "selected": "",
"footer": ""
}, },
"field": { "field": {
"name": { "name": {
@@ -3046,6 +3195,14 @@
"dead": "" "dead": ""
} }
}, },
"stats": {
"cpu": {
"label": ""
},
"memory": {
"label": ""
}
},
"containerImage": { "containerImage": {
"label": "Attēls" "label": "Attēls"
}, },
@@ -3054,6 +3211,7 @@
} }
}, },
"action": { "action": {
"title": "",
"start": { "start": {
"label": "Palaist", "label": "Palaist",
"notification": { "notification": {
@@ -3496,7 +3654,10 @@
"label": "" "label": ""
}, },
"certificates": { "certificates": {
"label": "" "label": "",
"hostnames": {
"label": ""
}
} }
}, },
"settings": { "settings": {
@@ -3894,6 +4055,29 @@
} }
}, },
"certificate": { "certificate": {
"field": {
"hostname": {
"label": ""
},
"subject": {
"label": ""
},
"issuer": {
"label": ""
},
"validFrom": {
"label": ""
},
"validTo": {
"label": ""
},
"serialNumber": {
"label": ""
},
"fingerprint": {
"label": ""
}
},
"page": { "page": {
"list": { "list": {
"title": "", "title": "",
@@ -3905,7 +4089,16 @@
"title": "", "title": "",
"description": "" "description": ""
}, },
"expires": "" "expires": "",
"toHostnames": ""
},
"hostnames": {
"title": "",
"description": "",
"noResults": {
"title": ""
},
"toCertificates": ""
} }
}, },
"action": { "action": {
@@ -3935,6 +4128,20 @@
"message": "" "message": ""
} }
} }
},
"removeHostname": {
"label": "",
"confirm": "",
"notification": {
"success": {
"title": "",
"message": ""
},
"error": {
"title": "",
"message": ""
}
}
} }
} }
} }
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff. Show more