Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
faf2525de5 | ||
|
|
3343468c55 | ||
|
|
27bd93fa8a | ||
|
|
e636e02d6a | ||
|
|
7f474683a5 | ||
|
|
4a07b3f866 | ||
|
|
d23196b430 | ||
|
|
ef40e75818 | ||
|
|
60accd66f6 | ||
|
|
4b6c69d48a | ||
|
|
c73ce1f704 | ||
|
|
ffa629064c | ||
|
|
dde41f6baf | ||
|
|
d32703910e | ||
|
|
a4914d09fd | ||
|
|
ed950e9302 | ||
|
|
bb681f7b5e | ||
|
|
72e976ee5e | ||
|
|
e6be8e1db3 | ||
|
|
5d494111df | ||
|
|
3ee408bf53 | ||
|
|
1b5ccb5293 | ||
|
|
cc6d421e7d | ||
|
|
c8d59d88e5 | ||
|
|
3dbf085e59 | ||
|
|
ff03220960 | ||
|
|
001f7a2a16 | ||
|
|
2780b1e794 | ||
|
|
59c092f800 | ||
|
|
4bc053cc17 | ||
|
|
baa652f314 | ||
|
|
2465676713 | ||
|
|
e45bef317a | ||
|
|
5d0966f466 | ||
|
|
9c377957ec | ||
|
|
ec3d560ad9 | ||
|
|
1dc1854cbf | ||
|
|
511551aee7 | ||
|
|
a9de2c39ff | ||
|
|
a14c3a2095 | ||
|
|
f63e64627c | ||
|
|
d66cccb0db | ||
|
|
0bfb8d845b | ||
|
|
3f3d31eb6a | ||
|
|
9a69644732 | ||
|
|
8eb44c9f23 | ||
|
|
c92bbd2da0 | ||
|
|
03adf538b0 | ||
|
|
949c7a40d9 | ||
|
|
6a819e38ed | ||
|
|
4b1699ab33 | ||
|
|
ab5e08a4b0 | ||
|
|
e7b21697ef | ||
|
|
f4e37134d8 | ||
|
|
58e686765c | ||
|
|
4f9ecae104 | ||
|
|
002063f6e1 | ||
|
|
183564176c | ||
|
|
b0bbd0d87a | ||
|
|
d0a112c791 | ||
|
|
952d4f71c9 | ||
|
|
6126fac915 | ||
|
|
a358377578 | ||
|
|
8a9bca39ea | ||
|
|
0dc1f7cf14 | ||
|
|
1aecf4f90d | ||
|
|
851a75aa54 | ||
|
|
91ae3ec84c | ||
|
|
6996f6d1a9 | ||
|
|
a16e9032f4 | ||
|
|
4b57d7b269 | ||
|
|
6d677828d4 | ||
|
|
28242d4335 | ||
|
|
83dd6c3d1b | ||
|
|
588c134d91 | ||
|
|
470448e5fc | ||
|
|
edbd301673 | ||
|
|
d3fba3eff4 | ||
|
|
04c15de0c8 | ||
|
|
abb011ff9a | ||
|
|
e858bad2ed | ||
|
|
d218170ec2 | ||
|
|
0094ec2567 | ||
|
|
50a7d24b1b | ||
|
|
f6d6acf8dc | ||
|
|
5a28535f59 | ||
|
|
9cdffc7ead | ||
|
|
fd62524db3 | ||
|
|
4f0ba7a191 | ||
|
|
ecda928bef | ||
|
|
bf88f0d091 | ||
|
|
98f8279b61 | ||
|
|
8e960324bc | ||
|
|
732bce72ae | ||
|
|
66ebb5061f | ||
|
|
fa8e704112 | ||
|
|
3f29a453b9 | ||
|
|
36b0f576e5 | ||
|
|
18c3ed559e | ||
|
|
6fca92ac49 | ||
|
|
42301b4a1e | ||
|
|
2394159f8b | ||
|
|
c2305d4e27 | ||
|
|
ba51d71c48 | ||
|
|
1cc6ecbce2 | ||
|
|
cf0d2d3cda | ||
|
|
553f192605 | ||
|
|
7f34c4323e | ||
|
|
49ef822a26 | ||
|
|
c4e5c3002b | ||
|
|
c00110e426 | ||
|
|
d4acb01efd | ||
|
|
ee983e8241 | ||
|
|
742d7bddf8 | ||
|
|
93ead1b53f | ||
|
|
11a42c176f | ||
|
|
47806c180e | ||
|
|
fc207b17dc | ||
|
|
39b025f763 | ||
|
|
e7012b6da4 | ||
|
|
d6ea8e8993 | ||
|
|
71dee5ca4b | ||
|
|
fe018732b5 | ||
|
|
021bb48e1a | ||
|
|
f57ba4c8bc | ||
|
|
6dd695ecf7 | ||
|
|
2726247e1b | ||
|
|
5ecc4db5da | ||
|
|
29884dda97 | ||
|
|
72633bf178 | ||
|
|
27fe82401b | ||
|
|
473a9f47f3 | ||
|
|
7fb7af12f4 | ||
|
|
380055e205 | ||
|
|
39bf0d036a | ||
|
|
5d8126d71e | ||
|
|
9020440193 | ||
|
|
bd8ac62c7a | ||
|
|
5a8653d850 | ||
|
|
dc754232bc | ||
|
|
9af542ee81 | ||
|
|
41a7182133 | ||
|
|
99358109ba | ||
|
|
df5b6fcb6a | ||
|
|
b03c9c1043 | ||
|
|
d68b80e6be | ||
|
|
f1143e54a0 | ||
|
|
54392dcea4 | ||
|
|
661afa72be | ||
|
|
d16e0ba7c1 | ||
|
|
e21b236d37 | ||
|
|
7e92f1bafa | ||
|
|
ee286c9556 | ||
|
|
68593335ec | ||
|
|
fb57d46b57 | ||
|
|
1724f9d26c | ||
|
|
90f6a2dd01 | ||
|
|
3f191da25c | ||
|
|
7c2f8b85bd | ||
|
|
c5db9db5d7 | ||
|
|
6a06a214be | ||
|
|
c08caeac5a | ||
|
|
c793bf1982 | ||
|
|
a369beb248 | ||
|
|
d736cf6daa | ||
|
|
3411354677 | ||
|
|
7c0a7428d8 | ||
|
|
5d394c849f | ||
|
|
9c7cfeb849 | ||
|
|
1eb47311fa | ||
|
|
1fe3450555 | ||
|
|
8b9832b2b8 | ||
|
|
57be43f51b | ||
|
|
824f443949 | ||
|
|
e9a35ba811 | ||
|
|
12f4e90e44 | ||
|
|
2ac75b23a4 | ||
|
|
430dc58068 | ||
|
|
8f1c3d8a2d | ||
|
|
b0bdf28016 | ||
|
|
01fd7b660c |
No files matched your search
@@ -12,6 +12,10 @@ AUTH_SECRET="supersecret"
|
||||
# or starting the project without any (which will show a randomly generated one).
|
||||
SECRET_ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
# Cron job API key is generated every time the container starts as it is required for communication between nextjs-api and tasks-api
|
||||
# export CRON_JOB_API_KEY=$(openssl rand -base64 32)
|
||||
# CRON_JOB_API_KEY="your-generated-api-key"
|
||||
|
||||
LOG_LEVEL='info'
|
||||
|
||||
# This is how you can use the sqlite driver:
|
||||
@@ -30,7 +34,8 @@ DB_URL='FULL_PATH_TO_YOUR_SQLITE_DB_FILE'
|
||||
# DB_PASSWORD='password'
|
||||
# DB_NAME='name-of-database'
|
||||
|
||||
# The below path can be used to store trusted certificates during development, it is not required and can be left empty.
|
||||
# The below path can be used to store trusted certificates, it is not required and can be left empty.
|
||||
# If it is empty, it will default to `/appdata/trusted-certificates` in production.
|
||||
# If it is used, please use the full path to the directory where the certificates are stored.
|
||||
# LOCAL_CERTIFICATE_PATH='FULL_PATH_TO_CERTIFICATES'
|
||||
|
||||
|
||||
@@ -31,6 +31,13 @@ body:
|
||||
label: Version
|
||||
description: What version of Homarr are you running?
|
||||
options:
|
||||
- 1.31.0
|
||||
- 1.30.1
|
||||
- 1.30.0
|
||||
- 1.29.0
|
||||
- 1.28.1
|
||||
- 1.28.0
|
||||
- 1.27.0
|
||||
- 1.26.0
|
||||
- 1.25.0
|
||||
- 1.24.0
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
matchPackagePatterns: ["^@homarr/"],
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
matchPackagePatterns: ["^zod$", "^drizzle-zod$", "^zod-form-data$"],
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
matchUpdateTypes: ["minor", "patch", "pin", "digest"],
|
||||
automerge: true,
|
||||
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
- uses: actions/setup-node@v4
|
||||
if: env.SKIP_RELEASE == 'false'
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 22.18.0
|
||||
- run: npm i -g pnpm
|
||||
if: env.SKIP_RELEASE == 'false'
|
||||
- name: Install dependencies
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
name: Update integration list
|
||||
|
||||
on:
|
||||
workflow_dispatch: { }
|
||||
push:
|
||||
paths:
|
||||
- packages/definitions/src/integration.ts
|
||||
branches:
|
||||
- dev
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
update-readme:
|
||||
concurrency:
|
||||
group: update-integration
|
||||
cancel-in-progress: false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Obtain token
|
||||
id: obtainToken
|
||||
uses: tibdex/github-app-token@v2
|
||||
with:
|
||||
private_key: ${{ secrets.HOMARR_UPDATE_CONTRIBUTORS_PRIVATE_KEY }}
|
||||
app_id: ${{ vars.HOMARR_UPDATE_CONTRIBUTORS_APP_ID }}
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
|
||||
- name: Setup
|
||||
uses: ./tooling/github/setup
|
||||
- run: pnpm run scripts:update-readme-integrations
|
||||
- name: Commit changes
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
|
||||
run: |
|
||||
git config --global user.email "210161987+homarr-update-contributors[bot]@users.noreply.github.com"
|
||||
git config --global user.name "Homarr Update Contributors"
|
||||
git add .
|
||||
git commit -m "chore: update integrations list readme"
|
||||
|
||||
- name: Create Pull Request
|
||||
id: create-pull-request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ steps.obtainToken.outputs.token }}
|
||||
branch: update-integrations-readme
|
||||
base: dev
|
||||
title: "chore: update integrations list readme"
|
||||
delete-branch: true
|
||||
body: |
|
||||
This PR automatically updates the list of integrations of Homarr in the README.md
|
||||
|
||||
- name: Install GitHub CLI
|
||||
run: sudo apt-get install -y gh
|
||||
|
||||
- name: Enable auto-merge
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.obtainToken.outputs.token }}
|
||||
run: |
|
||||
gh pr merge ${{steps.create-pull-request.outputs.pull-request-number}} --auto --squash
|
||||
@@ -1,3 +1,156 @@
|
||||
## [1.32.0](https://github.com/homarr-labs/homarr/compare/v1.31.0...v1.32.0) (2025-08-08)
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** add info endpoint ([#3737](https://github.com/homarr-labs/homarr/issues/3737)) ([baa652f](https://github.com/homarr-labs/homarr/commit/baa652f31493aad1490cf8e5d50bb04dc0006da1))
|
||||
* system resources widget ([#3538](https://github.com/homarr-labs/homarr/issues/3538)) ([3ee408b](https://github.com/homarr-labs/homarr/commit/3ee408bf53c45f0b2abf04449b3653ed3e9cf225))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** update dependency @gitbeaker/rest to ^43.4.0 ([#3806](https://github.com/homarr-labs/homarr/issues/3806)) ([c73ce1f](https://github.com/homarr-labs/homarr/commit/c73ce1f704aa1fcbc6beac4cfa80b080b6800373))
|
||||
* **deps:** update dependency @ianvs/prettier-plugin-sort-imports to ^4.6.0 ([#3797](https://github.com/homarr-labs/homarr/issues/3797)) ([a4914d0](https://github.com/homarr-labs/homarr/commit/a4914d09fd6c9fa6a602f9f76b71c096369a34cd))
|
||||
* **deps:** update dependency @ianvs/prettier-plugin-sort-imports to ^4.6.1 ([#3809](https://github.com/homarr-labs/homarr/issues/3809)) ([ef40e75](https://github.com/homarr-labs/homarr/commit/ef40e7581896df4371c1f13487f3830bb57f6886))
|
||||
* **deps:** update dependency jotai to ^2.13.0 ([#3763](https://github.com/homarr-labs/homarr/issues/3763)) ([c8d59d8](https://github.com/homarr-labs/homarr/commit/c8d59d88e5872783e767156eb063f329901fff6f))
|
||||
* **deps:** update dependency sass to ^1.90.0 ([#3794](https://github.com/homarr-labs/homarr/issues/3794)) ([bb681f7](https://github.com/homarr-labs/homarr/commit/bb681f7b5ebb4a0858dac40eacfcc809c04b3d5e))
|
||||
* **deps:** update dependency trpc-to-openapi to ^2.4.0 ([#3734](https://github.com/homarr-labs/homarr/issues/3734)) ([e45bef3](https://github.com/homarr-labs/homarr/commit/e45bef317a6ffae05d7a1685b1e6164e2ed09921))
|
||||
* **deps:** update dependency typescript-eslint to ^8.39.0 ([#3781](https://github.com/homarr-labs/homarr/issues/3781)) ([1b5ccb5](https://github.com/homarr-labs/homarr/commit/1b5ccb529358836682a1cccd4a3da14f612884b9))
|
||||
* **deps:** update dependency video.js to ^8.23.4 ([#3808](https://github.com/homarr-labs/homarr/issues/3808)) ([60accd6](https://github.com/homarr-labs/homarr/commit/60accd66f635ddb2f8c7a73faa865ee47aa40721))
|
||||
* **deps:** update mantine monorepo to ^8.2.3 ([#3789](https://github.com/homarr-labs/homarr/issues/3789)) ([e6be8e1](https://github.com/homarr-labs/homarr/commit/e6be8e1db3d843e3d0e5b6d54c64999fd45f103d))
|
||||
* **deps:** update mantine monorepo to ^8.2.4 ([#3803](https://github.com/homarr-labs/homarr/issues/3803)) ([ffa6290](https://github.com/homarr-labs/homarr/commit/ffa629064cdf202849d6f9c0ce645c6077c63e49))
|
||||
* **deps:** update nextjs monorepo to v15.4.6 ([#3799](https://github.com/homarr-labs/homarr/issues/3799)) ([d327039](https://github.com/homarr-labs/homarr/commit/d32703910e0228a70a55a84ab712d6bd58fe7149))
|
||||
* **deps:** update tanstack-query monorepo to ^5.84.2 ([#3810](https://github.com/homarr-labs/homarr/issues/3810)) ([d23196b](https://github.com/homarr-labs/homarr/commit/d23196b43034349d92cb9277633dd06b15ee0b7d))
|
||||
* **deps:** update testcontainers-node monorepo to ^11.5.0 ([#3738](https://github.com/homarr-labs/homarr/issues/3738)) ([4bc053c](https://github.com/homarr-labs/homarr/commit/4bc053cc17d5a38db4255f9913e389fe86831676))
|
||||
* **deps:** update testcontainers-node monorepo to ^11.5.1 ([#3796](https://github.com/homarr-labs/homarr/issues/3796)) ([ed950e9](https://github.com/homarr-labs/homarr/commit/ed950e9302450f33150d9800bc66e712bf8f6724))
|
||||
* **deps:** update trpc monorepo to ^11.4.4 ([#3777](https://github.com/homarr-labs/homarr/issues/3777)) ([cc6d421](https://github.com/homarr-labs/homarr/commit/cc6d421e7db52b994e9e62fa1f828c72b5a20d72))
|
||||
* **groups:** saving permissions with none activated causes error ([#3739](https://github.com/homarr-labs/homarr/issues/3739)) ([59c092f](https://github.com/homarr-labs/homarr/commit/59c092f8000f9a4e9fd70bde4176697dabb2e1c9))
|
||||
* not hardcode hero banner scroll ([#3741](https://github.com/homarr-labs/homarr/issues/3741)) ([001f7a2](https://github.com/homarr-labs/homarr/commit/001f7a2a165fade9deaafb4cb319aa27926685e5))
|
||||
* **opnsense:** switch secrets to api-key key and secret for easier understanding ([#3744](https://github.com/homarr-labs/homarr/issues/3744)) ([7f47468](https://github.com/homarr-labs/homarr/commit/7f474683a5e5b9ada978c055e57cd2b4114e17e0))
|
||||
* some integrations handle parse errors wrong ([#3746](https://github.com/homarr-labs/homarr/issues/3746)) ([72e976e](https://github.com/homarr-labs/homarr/commit/72e976ee5ea28e549b7674c71b9a284e905e455b))
|
||||
|
||||
## [1.31.0](https://github.com/homarr-labs/homarr/compare/v1.30.1...v1.31.0) (2025-08-01)
|
||||
|
||||
### Features
|
||||
|
||||
* OPNsense integration and widget ([#3424](https://github.com/homarr-labs/homarr/issues/3424)) ([1dc1854](https://github.com/homarr-labs/homarr/commit/1dc1854cbfa39f4f22755cb84e1d6882e7e73721))
|
||||
* **releases-widget:** add `Mark as read` action to mark releases as seen ([#3676](https://github.com/homarr-labs/homarr/issues/3676)) ([f63e646](https://github.com/homarr-labs/homarr/commit/f63e64627c79004b1e1bbb5a525fdde58f803da7))
|
||||
* **releases-widget:** add `Select/Deselect All` to `import from docker` screen ([#3674](https://github.com/homarr-labs/homarr/issues/3674)) ([949c7a4](https://github.com/homarr-labs/homarr/commit/949c7a40d934b2d58a24bf9842f44703e73474ee))
|
||||
* **releases-widget:** add new providers, Github Packages, linuxserver.io and Quay ([#3607](https://github.com/homarr-labs/homarr/issues/3607)) ([c92bbd2](https://github.com/homarr-labs/homarr/commit/c92bbd2da062221c3b5464838ad715c31a9d07b0))
|
||||
* **releases-widget:** Allow to display only the icon ([#3695](https://github.com/homarr-labs/homarr/issues/3695)) ([03adf53](https://github.com/homarr-labs/homarr/commit/03adf538b03270404956dc16b191069f913e54d1))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* characters are not considered Symbols when entering a new password ([#3689](https://github.com/homarr-labs/homarr/issues/3689)) ([6a819e3](https://github.com/homarr-labs/homarr/commit/6a819e38edca9f95b926a0162abdb6b873ddec08))
|
||||
* **deps:** update dependency drizzle-orm to ^0.44.4 ([#3708](https://github.com/homarr-labs/homarr/issues/3708)) ([6126fac](https://github.com/homarr-labs/homarr/commit/6126fac915197c19ea6d448da8c4fc1b06b1383b))
|
||||
* **deps:** update dependency ioredis to v5.7.0 ([#3718](https://github.com/homarr-labs/homarr/issues/3718)) ([4f9ecae](https://github.com/homarr-labs/homarr/commit/4f9ecae10406be4f6176947b517706843bd1c06d))
|
||||
* **deps:** update dependency ldapts to v8.0.9 ([#3703](https://github.com/homarr-labs/homarr/issues/3703)) ([1aecf4f](https://github.com/homarr-labs/homarr/commit/1aecf4f90d4776bfa93b6f601fca16a7da8ffaba))
|
||||
* **deps:** update dependency mysql2 to v3.14.3 ([#3711](https://github.com/homarr-labs/homarr/issues/3711)) ([952d4f7](https://github.com/homarr-labs/homarr/commit/952d4f71c9197cd88fa44ce5dbcf7d89f4c482d3))
|
||||
* **deps:** update dependency swagger-ui-react to ^5.27.1 ([#3725](https://github.com/homarr-labs/homarr/issues/3725)) ([ab5e08a](https://github.com/homarr-labs/homarr/commit/ab5e08a4b09845e3aa4818214bc0f9ce830a2942))
|
||||
* **deps:** update dependency undici to v7.13.0 ([#3717](https://github.com/homarr-labs/homarr/issues/3717)) ([b0bbd0d](https://github.com/homarr-labs/homarr/commit/b0bbd0d87ad6df7a9be83296060d8b0be6c091e0))
|
||||
* **deps:** update mantine monorepo to ^8.2.2 ([#3715](https://github.com/homarr-labs/homarr/issues/3715)) ([1835641](https://github.com/homarr-labs/homarr/commit/183564176c9421faea70dff199d0b6f81325bf70))
|
||||
* **deps:** update nextjs monorepo to v15.4.5 ([#3712](https://github.com/homarr-labs/homarr/issues/3712)) ([d0a112c](https://github.com/homarr-labs/homarr/commit/d0a112c7919cbcff9aaf2cc6b2dec8fd562246db))
|
||||
* **deps:** update react monorepo to v19.1.1 ([#3706](https://github.com/homarr-labs/homarr/issues/3706)) ([0dc1f7c](https://github.com/homarr-labs/homarr/commit/0dc1f7cf14c0ca49d5eb8d37060773c3dab4834a))
|
||||
* **deps:** update tanstack-query monorepo to ^5.83.1 ([#3719](https://github.com/homarr-labs/homarr/issues/3719)) ([f4e3713](https://github.com/homarr-labs/homarr/commit/f4e37134d806dac719012cb4dee19fb7e5daf7f2))
|
||||
* **deps:** update tanstack-query monorepo to ^5.84.0 ([#3723](https://github.com/homarr-labs/homarr/issues/3723)) ([e7b2169](https://github.com/homarr-labs/homarr/commit/e7b21697efb0f90c3539152beaea94416cbb6fef))
|
||||
* **deps:** update tanstack-query monorepo to ^5.84.1 ([#3729](https://github.com/homarr-labs/homarr/issues/3729)) ([511551a](https://github.com/homarr-labs/homarr/commit/511551aee7d5be9dadb70c596c5addbb646651cb))
|
||||
|
||||
### Reverts
|
||||
|
||||
* "feat(ping): ignore certificate error and show request durati… ([#3680](https://github.com/homarr-labs/homarr/issues/3680)) ([8eb44c9](https://github.com/homarr-labs/homarr/commit/8eb44c9f23584078b22605dac569387713dcd173))
|
||||
|
||||
## [1.30.1](https://github.com/homarr-labs/homarr/compare/v1.30.0...v1.30.1) (2025-07-25)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* [#3667](https://github.com/homarr-labs/homarr/issues/3667) plex media releases ([#3682](https://github.com/homarr-labs/homarr/issues/3682)) ([588c134](https://github.com/homarr-labs/homarr/commit/588c134d913f6811f7ed39d1954b586acc294932))
|
||||
* [#3678](https://github.com/homarr-labs/homarr/issues/3678) season number badge calendar ([#3681](https://github.com/homarr-labs/homarr/issues/3681)) ([470448e](https://github.com/homarr-labs/homarr/commit/470448e5fc1243dc78539dd8da87a974f504252a))
|
||||
* **deps:** update dependency @ctrl/deluge to ^7.1.1 ([#3677](https://github.com/homarr-labs/homarr/issues/3677)) ([04c15de](https://github.com/homarr-labs/homarr/commit/04c15de0c87be963f333ccb6aa1932c445793672))
|
||||
* **deps:** update dependency dotenv to ^17.2.1 ([#3684](https://github.com/homarr-labs/homarr/issues/3684)) ([d3fba3e](https://github.com/homarr-labs/homarr/commit/d3fba3eff4fd1fff3e86090436ecfd2fbcd93c28))
|
||||
* **deps:** update dependency ldapts to v8.0.8 ([#3665](https://github.com/homarr-labs/homarr/issues/3665)) ([5a28535](https://github.com/homarr-labs/homarr/commit/5a28535f59f6ea1928a941d5c11050752dd3ecc9))
|
||||
* **deps:** update dependency typescript-eslint to ^8.38.0 ([#3668](https://github.com/homarr-labs/homarr/issues/3668)) ([50a7d24](https://github.com/homarr-labs/homarr/commit/50a7d24b1b3a7cbfa6195525b10b994709b0beb3))
|
||||
* **deps:** update mantine monorepo to ^8.2.1 ([#3666](https://github.com/homarr-labs/homarr/issues/3666)) ([9cdffc7](https://github.com/homarr-labs/homarr/commit/9cdffc7ead2668ed259c1a38c774a3efea5a1f0e))
|
||||
* **deps:** update nextjs monorepo to v15.4.3 ([#3672](https://github.com/homarr-labs/homarr/issues/3672)) ([0094ec2](https://github.com/homarr-labs/homarr/commit/0094ec25677ca97f77920018c18f18a4b84812f8))
|
||||
* **deps:** update nextjs monorepo to v15.4.4 ([#3683](https://github.com/homarr-labs/homarr/issues/3683)) ([abb011f](https://github.com/homarr-labs/homarr/commit/abb011ff9a7b930dad2c382c4e454fba29633364))
|
||||
* **deps:** update testcontainers-node monorepo to ^11.3.2 ([#3671](https://github.com/homarr-labs/homarr/issues/3671)) ([d218170](https://github.com/homarr-labs/homarr/commit/d218170ec28a70b80c521efd1482164087d46e05))
|
||||
* **deps:** update testcontainers-node monorepo to ^11.4.0 ([#3679](https://github.com/homarr-labs/homarr/issues/3679)) ([e858bad](https://github.com/homarr-labs/homarr/commit/e858bad2eda8847269c1beee4cfbf957fa318fe4))
|
||||
|
||||
## [1.30.0](https://github.com/homarr-labs/homarr/compare/v1.29.0...v1.30.0) (2025-07-21)
|
||||
|
||||
### Features
|
||||
|
||||
* **infra:** add external redis ([#3639](https://github.com/homarr-labs/homarr/issues/3639)) ([8e96032](https://github.com/homarr-labs/homarr/commit/8e960324bcc43a64100fd9c6c1fd6822c7759160))
|
||||
* **widgets:** add media release widget ([#3219](https://github.com/homarr-labs/homarr/issues/3219)) ([66ebb50](https://github.com/homarr-labs/homarr/commit/66ebb5061fd219f9c804ef3a6bbe3372d296f740))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** update dependency @gitbeaker/rest to v43 ([#3623](https://github.com/homarr-labs/homarr/issues/3623)) ([732bce7](https://github.com/homarr-labs/homarr/commit/732bce72aee6c99d0ee94d04e173d378c2552a16))
|
||||
* **deps:** update dependency @tabler/icons-react to ^3.34.1 ([#3661](https://github.com/homarr-labs/homarr/issues/3661)) ([bf88f0d](https://github.com/homarr-labs/homarr/commit/bf88f0d0918b4073a5770ab3589e00e5f89cacf1))
|
||||
* **deps:** update nextjs monorepo to v15.4.2 ([#3654](https://github.com/homarr-labs/homarr/issues/3654)) ([42301b4](https://github.com/homarr-labs/homarr/commit/42301b4a1ed9e9f638b449a460862db9cd7ed50b))
|
||||
* **deps:** update testcontainers-node monorepo to ^11.3.0 ([#3652](https://github.com/homarr-labs/homarr/issues/3652)) ([2394159](https://github.com/homarr-labs/homarr/commit/2394159f8b546e8b6e2d3cdc7c6bd0f75483209c))
|
||||
* **deps:** update testcontainers-node monorepo to ^11.3.1 ([#3659](https://github.com/homarr-labs/homarr/issues/3659)) ([98f8279](https://github.com/homarr-labs/homarr/commit/98f8279b61013c312d492522e317bcf93f10e2a6))
|
||||
* improved import from docker parsing ([#3642](https://github.com/homarr-labs/homarr/issues/3642)) ([36b0f57](https://github.com/homarr-labs/homarr/commit/36b0f576e5a00726d76695fd3300710be6f925f8))
|
||||
* **security:** upgrade eslint-config-prettier to latest version without malicious code ([ecda928](https://github.com/homarr-labs/homarr/commit/ecda928bef407c67f01ce798c5f7a086cbd0dd9c))
|
||||
|
||||
## [1.29.0](https://github.com/homarr-labs/homarr/compare/v1.28.1...v1.29.0) (2025-07-18)
|
||||
|
||||
### Features
|
||||
|
||||
* **logs:** add log level selection to tools ui ([#3565](https://github.com/homarr-labs/homarr/issues/3565)) ([c4e5c30](https://github.com/homarr-labs/homarr/commit/c4e5c3002bd1c746cee496b5ba6d19159104b7f8))
|
||||
* **releases-widget:** show project description when release description is missing ([#3635](https://github.com/homarr-labs/homarr/issues/3635)) ([47806c1](https://github.com/homarr-labs/homarr/commit/47806c180ebc960eb1731c02ec6af42156831bd0))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** update dependency drizzle-orm to ^0.44.3 ([#3629](https://github.com/homarr-labs/homarr/issues/3629)) ([e7012b6](https://github.com/homarr-labs/homarr/commit/e7012b6da496a0f4b7aad527d1d05cd03d0bfcda))
|
||||
* **deps:** update dependency eslint-config-prettier to ^10.1.7 ([#3651](https://github.com/homarr-labs/homarr/issues/3651)) ([1cc6ecb](https://github.com/homarr-labs/homarr/commit/1cc6ecbce29348cf891dd8cfc29d4238ff5f7f78))
|
||||
* **deps:** update dependency ldapts to v8.0.6 ([#3628](https://github.com/homarr-labs/homarr/issues/3628)) ([71dee5c](https://github.com/homarr-labs/homarr/commit/71dee5ca4bca04acc9c295c373d1209641ef3d99))
|
||||
* **deps:** update dependency swagger-ui-react to ^5.27.0 ([#3638](https://github.com/homarr-labs/homarr/issues/3638)) ([ee983e8](https://github.com/homarr-labs/homarr/commit/ee983e8241d2f32c1dcbbea4930b18442f32a5bf))
|
||||
* **deps:** update dependency typescript-eslint to ^8.37.0 ([#3631](https://github.com/homarr-labs/homarr/issues/3631)) ([d6ea8e8](https://github.com/homarr-labs/homarr/commit/d6ea8e8993d130a03592473744e74be7b4c54a79))
|
||||
* **deps:** update dependency undici to v7.12.0 ([#3650](https://github.com/homarr-labs/homarr/issues/3650)) ([cf0d2d3](https://github.com/homarr-labs/homarr/commit/cf0d2d3cdaf495d7786c45ba4c79d49f356c0e37))
|
||||
* **deps:** update nextjs monorepo to v15.4.1 ([#3632](https://github.com/homarr-labs/homarr/issues/3632)) ([39b025f](https://github.com/homarr-labs/homarr/commit/39b025f7633391c74aedeb4c4dca10d42fb3b4d8))
|
||||
* **deps:** update turbo monorepo to ^2.5.5 ([#3641](https://github.com/homarr-labs/homarr/issues/3641)) ([d4acb01](https://github.com/homarr-labs/homarr/commit/d4acb01efd6a9341fb5550a08def42d82c1f0b92))
|
||||
|
||||
## [1.28.1](https://github.com/homarr-labs/homarr/compare/v1.28.0...v1.28.1) (2025-07-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** update tiptap monorepo to v2.26.1 ([#3603](https://github.com/homarr-labs/homarr/issues/3603)) ([473a9f4](https://github.com/homarr-labs/homarr/commit/473a9f47f352a532128c1bf2c02490e8e4c6ca7c))
|
||||
* **releases-widget:** fixed bug with changing a missing provider ([#3605](https://github.com/homarr-labs/homarr/issues/3605)) ([5ecc4db](https://github.com/homarr-labs/homarr/commit/5ecc4db5dabcfd4f953f3b436527d34ea9191eef))
|
||||
|
||||
## [1.28.0](https://github.com/homarr-labs/homarr/compare/v1.27.0...v1.28.0) (2025-07-11)
|
||||
|
||||
### Features
|
||||
|
||||
* **icon-color:** add icon color clear button ([#3593](https://github.com/homarr-labs/homarr/issues/3593)) ([5a8653d](https://github.com/homarr-labs/homarr/commit/5a8653d8500388d9392b150d62a56474c05843d7))
|
||||
* **notebook:** add placeholder, redo and undo button ([#3564](https://github.com/homarr-labs/homarr/issues/3564)) ([3411354](https://github.com/homarr-labs/homarr/commit/3411354677fedec6ff5b5b85eb25eacc94308425))
|
||||
* **ping:** ignore certificate error and show request duration ([#3546](https://github.com/homarr-labs/homarr/issues/3546)) ([1eb4731](https://github.com/homarr-labs/homarr/commit/1eb47311fa81184bd67830d0669d9f87d9922e70))
|
||||
* **releases-widget:** define providers as integrations ([#3253](https://github.com/homarr-labs/homarr/issues/3253)) ([5d8126d](https://github.com/homarr-labs/homarr/commit/5d8126d71eea61af9c023895cb911d24544f8066))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bookmarks:** wrong widget icon ([#3572](https://github.com/homarr-labs/homarr/issues/3572)) ([fb57d46](https://github.com/homarr-labs/homarr/commit/fb57d46b573cc9798469540f4823cbf73afd21a5))
|
||||
* **deps:** update dependency @ianvs/prettier-plugin-sort-imports to ^4.5.0 ([#3585](https://github.com/homarr-labs/homarr/issues/3585)) ([ee286c9](https://github.com/homarr-labs/homarr/commit/ee286c95563c99297b5419c005550936ca96757b))
|
||||
* **deps:** update dependency @ianvs/prettier-plugin-sort-imports to ^4.5.1 ([#3586](https://github.com/homarr-labs/homarr/issues/3586)) ([7e92f1b](https://github.com/homarr-labs/homarr/commit/7e92f1bafadf1188ee3ddc9d2dc9904f103aab4e))
|
||||
* **deps:** update dependency dotenv to ^17.1.0 ([#3567](https://github.com/homarr-labs/homarr/issues/3567)) ([a369beb](https://github.com/homarr-labs/homarr/commit/a369beb248e2cac1f1dcf32421efb48f241700a6))
|
||||
* **deps:** update dependency dotenv to ^17.2.0 ([#3578](https://github.com/homarr-labs/homarr/issues/3578)) ([1724f9d](https://github.com/homarr-labs/homarr/commit/1724f9d26c5761e3195d336eb451dd47855266a4))
|
||||
* **deps:** update dependency ldapts to v8.0.5 ([#3559](https://github.com/homarr-labs/homarr/issues/3559)) ([8b9832b](https://github.com/homarr-labs/homarr/commit/8b9832b2b81dcc1a4f9081755defe44fc0f38a1d))
|
||||
* **deps:** update dependency mysql2 to v3.14.2 ([#3592](https://github.com/homarr-labs/homarr/issues/3592)) ([d68b80e](https://github.com/homarr-labs/homarr/commit/d68b80e6be38366860de84778a45e5a43aae06eb))
|
||||
* **deps:** update dependency node-cron to ^4.2.1 ([#3590](https://github.com/homarr-labs/homarr/issues/3590)) ([e21b236](https://github.com/homarr-labs/homarr/commit/e21b236d37f076654768e88bc7ef139a3e51abbc))
|
||||
* **deps:** update dependency swagger-ui-react to ^5.26.1 ([#3554](https://github.com/homarr-labs/homarr/issues/3554)) ([12f4e90](https://github.com/homarr-labs/homarr/commit/12f4e90e440a8ea1708a2a9ef64a851ef977bd6c))
|
||||
* **deps:** update dependency swagger-ui-react to ^5.26.2 ([#3558](https://github.com/homarr-labs/homarr/issues/3558)) ([57be43f](https://github.com/homarr-labs/homarr/commit/57be43f51b7ef306b962299789194de68ec9e8ea))
|
||||
* **deps:** update dependency typescript-eslint to ^8.36.0 ([#3563](https://github.com/homarr-labs/homarr/issues/3563)) ([7c0a742](https://github.com/homarr-labs/homarr/commit/7c0a7428d85d11f3d2226d809ba04671ca713b72))
|
||||
* **deps:** update dependency zod to ^3.25.75 ([#3555](https://github.com/homarr-labs/homarr/issues/3555)) ([e9a35ba](https://github.com/homarr-labs/homarr/commit/e9a35ba811bd1807d63c5f0c760d470b20f4410f))
|
||||
* **deps:** update dependency zod to ^3.25.76 ([#3569](https://github.com/homarr-labs/homarr/issues/3569)) ([c793bf1](https://github.com/homarr-labs/homarr/commit/c793bf1982c3a484176860cebad80c721acd597d))
|
||||
* **deps:** update dependency zod-validation-error to ^3.5.3 ([#3600](https://github.com/homarr-labs/homarr/issues/3600)) ([9020440](https://github.com/homarr-labs/homarr/commit/9020440193595a5b437464957d9a3745fb200c93))
|
||||
* **deps:** update mantine monorepo to ^8.1.3 ([#3560](https://github.com/homarr-labs/homarr/issues/3560)) ([1fe3450](https://github.com/homarr-labs/homarr/commit/1fe34505550f401be97c9d84c383ea70bf39b937))
|
||||
* **deps:** update tanstack-query monorepo to ^5.82.0 ([#3577](https://github.com/homarr-labs/homarr/issues/3577)) ([90f6a2d](https://github.com/homarr-labs/homarr/commit/90f6a2dd014a73cd0131781b6db56a1056e563b6))
|
||||
* **deps:** update tanstack-query monorepo to ^5.83.0 ([#3599](https://github.com/homarr-labs/homarr/issues/3599)) ([bd8ac62](https://github.com/homarr-labs/homarr/commit/bd8ac62c7af034525803410751bfd5ab72094f45))
|
||||
* **deps:** update testcontainers-node monorepo to ^11.1.0 ([#3550](https://github.com/homarr-labs/homarr/issues/3550)) ([b0bdf28](https://github.com/homarr-labs/homarr/commit/b0bdf28016bae2ccfab24cab6df5b4846d1a8f48))
|
||||
* **deps:** update testcontainers-node monorepo to ^11.2.0 ([#3556](https://github.com/homarr-labs/homarr/issues/3556)) ([824f443](https://github.com/homarr-labs/homarr/commit/824f443949e75ec3f3edacb9093faefbdec47ef4))
|
||||
* **deps:** update testcontainers-node monorepo to ^11.2.1 ([#3562](https://github.com/homarr-labs/homarr/issues/3562)) ([5d394c8](https://github.com/homarr-labs/homarr/commit/5d394c849f5f47b47c595f73763e89d0a5d6247a))
|
||||
* **deps:** update tiptap monorepo to v2.25.0 ([#3552](https://github.com/homarr-labs/homarr/issues/3552)) ([430dc58](https://github.com/homarr-labs/homarr/commit/430dc580682cf0885fcd0ef2b7b81a0dfdf93425))
|
||||
* **deps:** update tiptap monorepo to v2.25.1 ([#3591](https://github.com/homarr-labs/homarr/issues/3591)) ([661afa7](https://github.com/homarr-labs/homarr/commit/661afa72be96c629cad4ab7f6007214b54d8ef6a))
|
||||
* **deps:** update tiptap monorepo to v2.26.0 ([#3596](https://github.com/homarr-labs/homarr/issues/3596)) ([df5b6fc](https://github.com/homarr-labs/homarr/commit/df5b6fcb6a6215f5c1cf92e034e27f6e32405b3e))
|
||||
* unable to change certificate path for running from source ([#3582](https://github.com/homarr-labs/homarr/issues/3582)) ([f1143e5](https://github.com/homarr-labs/homarr/commit/f1143e54a06e00a348e37b5633fad4cb6390cff7))
|
||||
|
||||
## [1.27.0](https://github.com/homarr-labs/homarr/compare/v1.26.0...v1.27.0) (2025-07-04)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:22.17.0-alpine AS base
|
||||
FROM node:22.18.0-alpine AS base
|
||||
|
||||
FROM base AS builder
|
||||
RUN apk add --no-cache libc6-compat
|
||||
@@ -10,8 +10,6 @@ RUN apk add --no-cache libc6-compat curl bash
|
||||
RUN apk update
|
||||
COPY . .
|
||||
|
||||
# Install working version of corepack (See https://github.com/nodejs/corepack/issues/612)
|
||||
RUN npm install -g corepack@0.31.0 && corepack --version
|
||||
RUN corepack enable pnpm && pnpm install --recursive --frozen-lockfile
|
||||
|
||||
# Copy static data as it is not part of the build
|
||||
@@ -19,8 +17,7 @@ COPY static-data ./static-data
|
||||
ARG SKIP_ENV_VALIDATION='true'
|
||||
ARG CI='true'
|
||||
ARG DISABLE_REDIS_LOGS='true'
|
||||
# Install working version of corepack (See https://github.com/nodejs/corepack/issues/612)
|
||||
RUN npm install -g corepack@0.31.0 && corepack --version
|
||||
|
||||
RUN corepack enable pnpm && pnpm build
|
||||
|
||||
FROM base AS runner
|
||||
@@ -67,6 +64,7 @@ ENV DB_URL='/appdata/db/db.sqlite'
|
||||
ENV DB_DIALECT='sqlite'
|
||||
ENV DB_DRIVER='better-sqlite3'
|
||||
ENV AUTH_PROVIDERS='credentials'
|
||||
ENV REDIS_IS_EXTERNAL='false'
|
||||
ENV NODE_ENV='production'
|
||||
|
||||
ENTRYPOINT [ "/app/entrypoint.sh" ]
|
||||
|
||||
@@ -25,15 +25,16 @@
|
||||
"@homarr/boards": "workspace:^0.1.0",
|
||||
"@homarr/certificates": "workspace:^0.1.0",
|
||||
"@homarr/common": "workspace:^0.1.0",
|
||||
"@homarr/core": "workspace:^0.1.0",
|
||||
"@homarr/cron-job-status": "workspace:^0.1.0",
|
||||
"@homarr/db": "workspace:^0.1.0",
|
||||
"@homarr/definitions": "workspace:^0.1.0",
|
||||
"@homarr/docker": "workspace:^0.1.0",
|
||||
"@homarr/env": "workspace:^0.1.0",
|
||||
"@homarr/form": "workspace:^0.1.0",
|
||||
"@homarr/forms-collection": "workspace:^0.1.0",
|
||||
"@homarr/gridstack": "^1.12.0",
|
||||
"@homarr/icons": "workspace:^0.1.0",
|
||||
"@homarr/image-proxy": "workspace:^0.1.0",
|
||||
"@homarr/integrations": "workspace:^0.1.0",
|
||||
"@homarr/log": "workspace:^",
|
||||
"@homarr/modals": "workspace:^0.1.0",
|
||||
@@ -49,59 +50,59 @@
|
||||
"@homarr/ui": "workspace:^0.1.0",
|
||||
"@homarr/validation": "workspace:^0.1.0",
|
||||
"@homarr/widgets": "workspace:^0.1.0",
|
||||
"@mantine/colors-generator": "^8.1.2",
|
||||
"@mantine/core": "^8.1.2",
|
||||
"@mantine/dropzone": "^8.1.2",
|
||||
"@mantine/hooks": "^8.1.2",
|
||||
"@mantine/modals": "^8.1.2",
|
||||
"@mantine/tiptap": "^8.1.2",
|
||||
"@mantine/colors-generator": "^8.2.4",
|
||||
"@mantine/core": "^8.2.4",
|
||||
"@mantine/dropzone": "^8.2.4",
|
||||
"@mantine/hooks": "^8.2.4",
|
||||
"@mantine/modals": "^8.2.4",
|
||||
"@mantine/tiptap": "^8.2.4",
|
||||
"@million/lint": "1.0.14",
|
||||
"@tabler/icons-react": "^3.34.0",
|
||||
"@tanstack/react-query": "^5.81.5",
|
||||
"@tanstack/react-query-devtools": "^5.81.5",
|
||||
"@tanstack/react-query-next-experimental": "^5.81.5",
|
||||
"@trpc/client": "^11.4.3",
|
||||
"@trpc/next": "^11.4.3",
|
||||
"@trpc/react-query": "^11.4.3",
|
||||
"@trpc/server": "^11.4.3",
|
||||
"@tabler/icons-react": "^3.34.1",
|
||||
"@tanstack/react-query": "^5.84.2",
|
||||
"@tanstack/react-query-devtools": "^5.84.2",
|
||||
"@tanstack/react-query-next-experimental": "^5.84.2",
|
||||
"@trpc/client": "^11.4.4",
|
||||
"@trpc/next": "^11.4.4",
|
||||
"@trpc/react-query": "^11.4.4",
|
||||
"@trpc/server": "^11.4.4",
|
||||
"@xterm/addon-canvas": "^0.7.0",
|
||||
"@xterm/addon-fit": "0.10.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"chroma-js": "^3.1.2",
|
||||
"clsx": "^2.1.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"dotenv": "^17.0.1",
|
||||
"dotenv": "^17.2.1",
|
||||
"flag-icons": "^7.5.0",
|
||||
"glob": "^11.0.3",
|
||||
"jotai": "^2.12.5",
|
||||
"jotai": "^2.13.0",
|
||||
"mantine-react-table": "2.0.0-beta.9",
|
||||
"next": "15.3.5",
|
||||
"next": "15.4.6",
|
||||
"postcss-preset-mantine": "^1.18.0",
|
||||
"prismjs": "^1.30.0",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"react-error-boundary": "^6.0.0",
|
||||
"react-simple-code-editor": "^0.14.1",
|
||||
"sass": "^1.89.2",
|
||||
"sass": "^1.90.0",
|
||||
"superjson": "2.2.2",
|
||||
"swagger-ui-react": "^5.26.0",
|
||||
"swagger-ui-react": "^5.27.1",
|
||||
"use-deep-compare-effect": "^1.8.1",
|
||||
"zod": "^3.25.74"
|
||||
"zod": "^3.25.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"@types/chroma-js": "3.1.1",
|
||||
"@types/node": "^22.16.0",
|
||||
"@types/node": "^22.17.1",
|
||||
"@types/prismjs": "^1.26.5",
|
||||
"@types/react": "19.1.8",
|
||||
"@types/react-dom": "19.1.6",
|
||||
"@types/react": "19.1.9",
|
||||
"@types/react-dom": "19.1.7",
|
||||
"@types/swagger-ui-react": "^5.18.0",
|
||||
"concurrently": "^9.2.0",
|
||||
"eslint": "^9.30.1",
|
||||
"eslint": "^9.32.0",
|
||||
"node-loader": "^2.1.0",
|
||||
"prettier": "^3.6.2",
|
||||
"typescript": "^5.8.3"
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
useMantineTheme,
|
||||
} from "@mantine/core";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import { IconX } from "@tabler/icons-react";
|
||||
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
@@ -102,12 +103,25 @@ export const ColorSettingsContent = ({ board }: Props) => {
|
||||
</InputWrapper>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={{ sm: 12, md: 6 }}>
|
||||
<ColorInput
|
||||
label={t("board.field.iconColor.label")}
|
||||
format="hex"
|
||||
swatches={Object.values(theme.colors).map((color) => color[6])}
|
||||
{...form.getInputProps("iconColor")}
|
||||
/>
|
||||
<Group align="end">
|
||||
<ColorInput
|
||||
label={t("board.field.iconColor.label")}
|
||||
format="hex"
|
||||
swatches={Object.values(theme.colors).map((color) => color[6])}
|
||||
flex={1}
|
||||
{...form.getInputProps("iconColor")}
|
||||
/>
|
||||
<Button
|
||||
variant="subtle"
|
||||
leftSection={<IconX />}
|
||||
onClick={() => form.setFieldValue("iconColor", "")}
|
||||
disabled={!form.values.iconColor}
|
||||
>
|
||||
{t("board.field.clearColor.label")}
|
||||
</Button>
|
||||
</Group>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={{ sm: 12, md: 6 }}>
|
||||
<Select
|
||||
label={t("board.field.itemRadius.label")}
|
||||
description={t("board.field.itemRadius.description")}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { Button, Fieldset, Grid, Group, Input, NumberInput, Slider, Stack, Text, TextInput } from "@mantine/core";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { createId } from "@homarr/db/client";
|
||||
import { createId } from "@homarr/common";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
import { boardSaveLayoutsSchema } from "@homarr/validation/board";
|
||||
|
||||
@@ -1,37 +1,16 @@
|
||||
import { Box, Grid, GridCol, Group, Image, Stack, Title } from "@mantine/core";
|
||||
|
||||
import { splitToNChunks } from "@homarr/common";
|
||||
import { integrationDefs } from "@homarr/definitions";
|
||||
|
||||
import classes from "./hero-banner.module.css";
|
||||
|
||||
const icons = [
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/homarr.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/sabnzbd.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/deluge.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/radarr.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/sonarr.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/lidarr.svg",
|
||||
"https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/pihole.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/dashdot.png",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/overseerr.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/plex.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/jellyfin.svg",
|
||||
"https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/homeassistant.svg",
|
||||
"https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/freshrss.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/readarr.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/transmission.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/qbittorrent.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/nzbget.png",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/openmediavault.svg",
|
||||
"https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/docker.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/jellyseerr.svg",
|
||||
"https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/adguardhome.svg",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/tdarr.png",
|
||||
"https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/prowlarr.svg",
|
||||
];
|
||||
const icons = Object.values(integrationDefs)
|
||||
.filter((int) => int.name !== "Mock")
|
||||
.map((int) => int.iconUrl);
|
||||
|
||||
const countIconGroups = 3;
|
||||
const animationDurationInSeconds = 12;
|
||||
const animationDurationInSeconds = icons.length;
|
||||
const arrayInChunks = splitToNChunks(icons, countIconGroups);
|
||||
|
||||
export const HeroBanner = () => {
|
||||
@@ -61,12 +40,26 @@ export const HeroBanner = () => {
|
||||
}}
|
||||
>
|
||||
{arrayInChunks[columnIndex]?.map((icon, index) => (
|
||||
<Image key={`grid-column-${columnIndex}-scroll-1-${index}`} src={icon} radius="md" w={50} h={50} />
|
||||
<Image
|
||||
key={`grid-column-${columnIndex}-scroll-1-${index}`}
|
||||
src={icon}
|
||||
radius="md"
|
||||
fit={"contain"}
|
||||
w={50}
|
||||
h={50}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* This is used for making the animation seem seamless */}
|
||||
{arrayInChunks[columnIndex]?.map((icon, index) => (
|
||||
<Image key={`grid-column-${columnIndex}-scroll-2-${index}`} src={icon} radius="md" w={50} h={50} />
|
||||
<Image
|
||||
key={`grid-column-${columnIndex}-scroll-2-${index}`}
|
||||
src={icon}
|
||||
radius="md"
|
||||
fit={"contain"}
|
||||
w={50}
|
||||
h={50}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
</GridCol>
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import { IconGrid3x3, IconKey, IconMessage, IconPassword, IconServer, IconUser } from "@tabler/icons-react";
|
||||
import {
|
||||
IconGrid3x3,
|
||||
IconKey,
|
||||
IconMessage,
|
||||
IconPassword,
|
||||
IconPasswordUser,
|
||||
IconServer,
|
||||
IconUser,
|
||||
} from "@tabler/icons-react";
|
||||
|
||||
import type { IntegrationSecretKind } from "@homarr/definitions";
|
||||
import type { TablerIcon } from "@homarr/ui";
|
||||
@@ -9,5 +17,8 @@ export const integrationSecretIcons = {
|
||||
password: IconPassword,
|
||||
realm: IconServer,
|
||||
tokenId: IconGrid3x3,
|
||||
personalAccessToken: IconPasswordUser,
|
||||
topic: IconMessage,
|
||||
opnsenseApiKey: IconKey,
|
||||
opnsenseApiSecret: IconPassword,
|
||||
} satisfies Record<IntegrationSecretKind, TablerIcon>;
|
||||
@@ -4,8 +4,7 @@ import { IconAlertTriangle, IconCheck, IconCopy, IconExclamationCircle, IconRepe
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useSession } from "@homarr/auth/client";
|
||||
import { getMantineColor } from "@homarr/common";
|
||||
import { createId } from "@homarr/db/client";
|
||||
import { createId, getMantineColor } from "@homarr/common";
|
||||
import { createDocumentationLink } from "@homarr/definitions";
|
||||
import { createModal, useConfirmModal, useModalAction } from "@homarr/modals";
|
||||
import { AddCertificateModal } from "@homarr/modals-collection";
|
||||
|
||||
@@ -21,7 +21,13 @@ import { z } from "zod";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { revalidatePathActionAsync } from "@homarr/common/client";
|
||||
import type { IntegrationKind, IntegrationSecretKind } from "@homarr/definitions";
|
||||
import { getAllSecretKindOptions, getIconUrl, getIntegrationName, integrationDefs } from "@homarr/definitions";
|
||||
import {
|
||||
getAllSecretKindOptions,
|
||||
getIconUrl,
|
||||
getIntegrationDefaultUrl,
|
||||
getIntegrationName,
|
||||
integrationDefs,
|
||||
} from "@homarr/definitions";
|
||||
import type { UseFormReturnType } from "@homarr/form";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
|
||||
@@ -54,7 +60,7 @@ export const NewIntegrationForm = ({ searchParams }: NewIntegrationFormProps) =>
|
||||
const form = useZodForm(formSchema, {
|
||||
initialValues: {
|
||||
name: searchParams.name ?? getIntegrationName(searchParams.kind),
|
||||
url: searchParams.url ?? "",
|
||||
url: searchParams.url ?? getIntegrationDefaultUrl(searchParams.kind) ?? "",
|
||||
secrets: secretKinds[0].map((kind) => ({
|
||||
kind,
|
||||
value: "",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { SimpleGrid, Skeleton, Stack, Title } from "@mantine/core";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { createId } from "@homarr/db/client";
|
||||
import { createId } from "@homarr/common";
|
||||
import type { KubernetesLabelResourceType } from "@homarr/definitions";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { MantineReactTable } from "mantine-react-table";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { createId } from "@homarr/db/client";
|
||||
import { createId } from "@homarr/common";
|
||||
import type { KubernetesIngress } from "@homarr/definitions";
|
||||
import type { ScopedTranslationFunction } from "@homarr/translation";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
|
||||
@@ -8,7 +8,7 @@ import { MantineReactTable } from "mantine-react-table";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { createId } from "@homarr/db/client";
|
||||
import { createId } from "@homarr/common";
|
||||
import type { KubernetesService } from "@homarr/definitions";
|
||||
import type { ScopedTranslationFunction } from "@homarr/translation";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
"use client";
|
||||
|
||||
import { Select } from "@mantine/core";
|
||||
|
||||
import type { LogLevel } from "@homarr/log/constants";
|
||||
import { logLevelConfiguration, logLevels } from "@homarr/log/constants";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
|
||||
import { useLogContext } from "./log-context";
|
||||
|
||||
export const LogLevelSelection = () => {
|
||||
const { level, setLevel } = useLogContext();
|
||||
const t = useI18n();
|
||||
|
||||
return (
|
||||
<Select
|
||||
data={logLevels.map((level) => ({
|
||||
value: level,
|
||||
label: `${logLevelConfiguration[level].prefix} ${t(`log.level.option.${level}`)}`,
|
||||
}))}
|
||||
value={level}
|
||||
onChange={(value) => setLevel(value as LogLevel)}
|
||||
checkIconPosition="right"
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
"use client";
|
||||
|
||||
import type { PropsWithChildren } from "react";
|
||||
import { createContext, useContext, useMemo, useState } from "react";
|
||||
|
||||
import type { LogLevel } from "@homarr/log/constants";
|
||||
import { logLevels } from "@homarr/log/constants";
|
||||
|
||||
const LogContext = createContext<{
|
||||
level: LogLevel;
|
||||
setLevel: (level: LogLevel) => void;
|
||||
activeLevels: LogLevel[];
|
||||
} | null>(null);
|
||||
|
||||
interface LogContextProviderProps extends PropsWithChildren {
|
||||
defaultLevel: LogLevel;
|
||||
}
|
||||
|
||||
export const LogContextProvider = ({ defaultLevel, children }: LogContextProviderProps) => {
|
||||
const [level, setLevel] = useState(defaultLevel);
|
||||
const activeLevels = useMemo(() => logLevels.slice(0, logLevels.indexOf(level) + 1), [level]);
|
||||
|
||||
return <LogContext.Provider value={{ level, setLevel, activeLevels }}>{children}</LogContext.Provider>;
|
||||
};
|
||||
|
||||
export const useLogContext = () => {
|
||||
const context = useContext(LogContext);
|
||||
if (!context) {
|
||||
throw new Error("useLogContext must be used within a LogContextProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box } from "@mantine/core";
|
||||
import { Box, Group } from "@mantine/core";
|
||||
|
||||
import { getScopedI18n } from "@homarr/translation/server";
|
||||
|
||||
@@ -7,11 +7,14 @@ import "@xterm/xterm/css/xterm.css";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
import { auth } from "@homarr/auth/next";
|
||||
import { env } from "@homarr/log/env";
|
||||
|
||||
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
|
||||
import { fullHeightWithoutHeaderAndFooter } from "~/constants";
|
||||
import { createMetaTitle } from "~/metadata";
|
||||
import { ClientSideTerminalComponent } from "./client";
|
||||
import { LogLevelSelection } from "./level-selection";
|
||||
import { LogContextProvider } from "./log-context";
|
||||
|
||||
export async function generateMetadata() {
|
||||
const session = await auth();
|
||||
@@ -32,11 +35,14 @@ export default async function LogsManagementPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<DynamicBreadcrumb />
|
||||
<LogContextProvider defaultLevel={env.LOG_LEVEL}>
|
||||
<Group justify="space-between" align="center" wrap="nowrap">
|
||||
<DynamicBreadcrumb />
|
||||
<LogLevelSelection />
|
||||
</Group>
|
||||
<Box style={{ borderRadius: 6 }} h={fullHeightWithoutHeaderAndFooter} p="md" bg="black">
|
||||
<ClientSideTerminalComponent />
|
||||
</Box>
|
||||
</>
|
||||
</LogContextProvider>
|
||||
);
|
||||
}
|
||||
@@ -8,22 +8,29 @@ import { Terminal } from "@xterm/xterm";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
|
||||
import { useLogContext } from "./log-context";
|
||||
import classes from "./terminal.module.css";
|
||||
|
||||
export const TerminalComponent = () => {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const { activeLevels } = useLogContext();
|
||||
|
||||
const terminalRef = useRef<Terminal>(null);
|
||||
clientApi.log.subscribe.useSubscription(undefined, {
|
||||
onData(data) {
|
||||
terminalRef.current?.writeln(`${data.timestamp} ${data.level} ${data.message}`);
|
||||
terminalRef.current?.refresh(0, terminalRef.current.rows - 1);
|
||||
clientApi.log.subscribe.useSubscription(
|
||||
{
|
||||
levels: activeLevels,
|
||||
},
|
||||
onError(err) {
|
||||
// This makes sense as logging might cause an infinite loop
|
||||
alert(err);
|
||||
{
|
||||
onData(data) {
|
||||
terminalRef.current?.writeln(data.message);
|
||||
terminalRef.current?.refresh(0, terminalRef.current.rows - 1);
|
||||
},
|
||||
onError(err) {
|
||||
// This makes sense as logging might cause an infinite loop
|
||||
alert(err);
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current) {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
import { ImageProxy } from "@homarr/image-proxy";
|
||||
|
||||
export const GET = async (_request: Request, props: { params: Promise<{ id: string }> }) => {
|
||||
const { id } = await props.params;
|
||||
|
||||
const imageProxy = new ImageProxy();
|
||||
const image = await imageProxy.forwardImageAsync(id);
|
||||
if (!image) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return new Response(image, {
|
||||
headers: {
|
||||
"Cache-Control": "public, max-age=3600, immutable", // Cache for 1 hour
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -23,7 +23,7 @@ export async function GET(_req: NextRequest, props: { params: Promise<{ id: stri
|
||||
headers.set("Content-Type", image.contentType);
|
||||
headers.set("Content-Length", image.content.length.toString());
|
||||
|
||||
return new NextResponse(image.content, {
|
||||
return new NextResponse(new Uint8Array(image.content), {
|
||||
status: 200,
|
||||
headers,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getBoardLayouts } from "@homarr/boards/context";
|
||||
import { createId } from "@homarr/common";
|
||||
import type { Modify } from "@homarr/common/types";
|
||||
import { createId } from "@homarr/db/client";
|
||||
import type { WidgetKind } from "@homarr/definitions";
|
||||
|
||||
import type { Board, EmptySection, Item, ItemLayout } from "~/app/[locale]/boards/_types";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createId } from "@homarr/db/client";
|
||||
import { createId } from "@homarr/common";
|
||||
|
||||
import type { Board, EmptySection, ItemLayout, Section } from "~/app/[locale]/boards/_types";
|
||||
import { getFirstEmptyPosition } from "./empty-position";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createId } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
|
||||
import type { Board, DynamicSection, EmptySection, Item, Section } from "~/app/[locale]/boards/_types";
|
||||
import { DynamicSectionMockBuilder } from "./dynamic-section-mock";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createId } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
|
||||
import type { CategorySection } from "~/app/[locale]/boards/_types";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createId } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
|
||||
import type { DynamicSection } from "~/app/[locale]/boards/_types";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createId } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
|
||||
import type { EmptySection } from "~/app/[locale]/boards/_types";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createId } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
|
||||
import type { Item } from "~/app/[locale]/boards/_types";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createId } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
|
||||
import type { Board } from "~/app/[locale]/boards/_types";
|
||||
|
||||
|
||||
@@ -21,6 +21,12 @@ interface BoardItemContentProps {
|
||||
item: SectionItem;
|
||||
}
|
||||
|
||||
const getOverflowFromKind = (kind: SectionItem["kind"]) => {
|
||||
if (kind === "iframe") return "hidden";
|
||||
if (kind === "systemResources") return "visible";
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const BoardItemContent = ({ item }: BoardItemContentProps) => {
|
||||
const { ref, width, height } = useElementSize<HTMLDivElement>();
|
||||
const board = useRequiredBoard();
|
||||
@@ -41,7 +47,7 @@ export const BoardItemContent = ({ item }: BoardItemContentProps) => {
|
||||
root: {
|
||||
"--opacity": board.opacity / 100,
|
||||
containerType: "size",
|
||||
overflow: item.kind === "iframe" ? "hidden" : undefined,
|
||||
overflow: getOverflowFromKind(item.kind),
|
||||
"--border-color": item.advancedOptions.borderColor !== "" ? item.advancedOptions.borderColor : undefined,
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback } from "react";
|
||||
|
||||
import { useUpdateBoard } from "@homarr/boards/updater";
|
||||
import { createId } from "@homarr/db/client";
|
||||
import { createId } from "@homarr/common";
|
||||
|
||||
import type { CategorySection, EmptySection, Section } from "~/app/[locale]/boards/_types";
|
||||
import type { MoveCategoryInput } from "./actions/move-category";
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useCallback } from "react";
|
||||
|
||||
import { fetchApi } from "@homarr/api/client";
|
||||
import { getCurrentLayout, useRequiredBoard } from "@homarr/boards/context";
|
||||
import { createId } from "@homarr/db/client";
|
||||
import { createId } from "@homarr/common";
|
||||
import { useConfirmModal, useModalAction } from "@homarr/modals";
|
||||
import { useSettings } from "@homarr/settings";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getBoardLayouts } from "@homarr/boards/context";
|
||||
import { createId } from "@homarr/db/client";
|
||||
import { createId } from "@homarr/common";
|
||||
|
||||
import type { Board, DynamicSection, DynamicSectionLayout, EmptySection } from "~/app/[locale]/boards/_types";
|
||||
import { getFirstEmptyPosition } from "~/components/board/items/actions/empty-position";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { createEnv } from "@homarr/env";
|
||||
import { createBooleanSchema } from "@homarr/env/schemas";
|
||||
import { createBooleanSchema, createEnv } from "@homarr/core/infrastructure/env";
|
||||
|
||||
export const env = createEnv({
|
||||
server: {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"main": "./src/main.ts",
|
||||
"types": "./src/main.ts",
|
||||
"scripts": {
|
||||
"build": "esbuild src/main.ts --bundle --platform=node --loader:.scss=text --external:*.node --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 --external:bcrypt --outfile=tasks.cjs",
|
||||
"clean": "rm -rf .turbo node_modules",
|
||||
"dev": "pnpm with-env tsx ./src/main.ts",
|
||||
"format": "prettier --check . --ignore-path ../../.gitignore",
|
||||
@@ -36,21 +36,21 @@
|
||||
"@homarr/validation": "workspace:^0.1.0",
|
||||
"@homarr/widgets": "workspace:^0.1.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"dotenv": "^17.0.1",
|
||||
"dotenv": "^17.2.1",
|
||||
"fastify": "^5.4.0",
|
||||
"superjson": "2.2.2",
|
||||
"undici": "7.11.0"
|
||||
"undici": "7.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"@types/node": "^22.16.0",
|
||||
"dotenv-cli": "^8.0.0",
|
||||
"esbuild": "^0.25.5",
|
||||
"eslint": "^9.30.1",
|
||||
"@types/node": "^22.17.1",
|
||||
"dotenv-cli": "^10.0.0",
|
||||
"esbuild": "^0.25.8",
|
||||
"eslint": "^9.32.0",
|
||||
"prettier": "^3.6.2",
|
||||
"tsx": "4.20.3",
|
||||
"typescript": "^5.8.3"
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
"@homarr/log": "workspace:^",
|
||||
"@homarr/redis": "workspace:^0.1.0",
|
||||
"@homarr/validation": "workspace:^0.1.0",
|
||||
"dotenv": "^17.0.1",
|
||||
"dotenv": "^17.2.1",
|
||||
"tsx": "4.20.3",
|
||||
"ws": "^8.18.3"
|
||||
},
|
||||
@@ -34,9 +34,9 @@
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"@types/ws": "^8.18.1",
|
||||
"esbuild": "^0.25.5",
|
||||
"eslint": "^9.30.1",
|
||||
"esbuild": "^0.25.8",
|
||||
"eslint": "^9.32.0",
|
||||
"prettier": "^3.6.2",
|
||||
"typescript": "^5.8.3"
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
<!-- Project Title -->
|
||||
[](https://homarr.dev/)
|
||||

|
||||
|
||||
<!-- Badges -->
|
||||
<p align="center">
|
||||
@@ -20,10 +19,6 @@
|
||||
|
||||
<!-- Links -->
|
||||
<p align="center">
|
||||
<a href="https://demo.homarr.dev/">
|
||||
<strong>Demo ✨</strong>
|
||||
</a>
|
||||
•
|
||||
<a href="https://homarr.dev/docs/category/installation-1/">
|
||||
<strong>Install 💻</strong>
|
||||
</a> •
|
||||
@@ -35,8 +30,7 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
||||
[](https://homarr.dev/)
|
||||

|
||||
|
||||
- 🖌️ Highly customizable with an extensive drag and drop grid system
|
||||
- ✨ Integrates seamlessly with your favorite self-hosted applications
|
||||
@@ -53,44 +47,268 @@
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
[](https://homarr.dev/docs/category/widgets)
|
||||

|
||||
|
||||
Homarr has a [built-in collection of widgets and integrations](https://homarr.dev/docs/category/integrations), that connect to your applications and enable you to control them directly from the dashboard.
|
||||
<!-- AUTO_GENERATE_INTEGRATION_LIST_START -->
|
||||
|
||||
- 📥 **Torrent clients**
|
||||
- [Deluge](https://homarr.dev/docs/integrations/torrent#deluge)
|
||||
- [Transmission](https://homarr.dev/docs/integrations/torrent#transmission)
|
||||
- [qBittorent](https://homarr.dev/docs/integrations/torrent#qbittorrent-integration)
|
||||
- 📥 **Usenet clients**
|
||||
- [SABnzbd](https://homarr.dev/docs/integrations/usenet#sabnzbd)
|
||||
- [NZBGet](https://homarr.dev/docs/integrations/usenet#nzbget)
|
||||
- 📺 **Media servers**
|
||||
- [Plex](https://homarr.dev/docs/integrations/media-server/#plex)
|
||||
- [Jellyfin](https://homarr.dev/docs/integrations/media-server#jellyfin-and-emby)
|
||||
- 📚 **Media collection managers**
|
||||
- [Sonarr](https://homarr.dev/docs/integrations/servarr#sonarr)
|
||||
- [Radarr](https://homarr.dev/docs/integrations/servarr#radarr)
|
||||
- [Lidarr](https://homarr.dev/docs/integrations/servarr#lidarr)
|
||||
- [Readarr](https://homarr.dev/docs/integrations/servarr#readarr)
|
||||
- 🎞️ **Media request managers**
|
||||
- [Overseerr](https://homarr.dev/docs/integrations/media-requester)
|
||||
- [Jellyseerr](https://homarr.dev/docs/integrations/media-requester)
|
||||
- 🚫 **DNS ad-blockers**
|
||||
- [Pihole](https://homarr.dev/docs/integrations/dns#pihole)
|
||||
- [AdGuard Home](https://homarr.dev/docs/integrations/dns#adguard-home)
|
||||
- 🖥️ **Monitoring**
|
||||
- [Dash.](https://homarr.dev/docs/integrations/hardware)
|
||||
- [OpenMediaVault.](https://homarr.dev/docs/integrations/hardware/#openmediavault)
|
||||
- [Proxmox.](https://homarr.dev/docs/integrations/hardware/#proxmox)
|
||||
- 🐳 **Container management**:
|
||||
- [Docker](https://homarr.dev/docs/integrations/containers)
|
||||
<div align="center">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/adguard-home" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/adguard-home.svg" alt="AdGuard Home" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">AdGuard<br/>Home</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/aria2" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/PapirusDevelopmentTeam/papirus_icons@latest/src/system_downloads_3.svg" alt="Aria2" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Aria2</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/codeberg" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/codeberg.svg" alt="Codeberg" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Codeberg</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/dash-dot" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/dashdot.png" alt="Dash." width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Dash.</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/deluge" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/deluge.svg" alt="Deluge" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Deluge</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/docker-hub" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/docker.svg" alt="Docker Hub" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Docker<br/>Hub</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/emby" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/emby.svg" alt="Emby" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Emby</p>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr><td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/github" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/github.svg" alt="Github" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Github</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/github" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/github.svg" alt="GitHub Container Registry" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">GitHub<br/>Container<br/>Registry</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/gitlab" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/gitlab.svg" alt="Gitlab" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Gitlab</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/home-assistant" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/home-assistant.svg" alt="Home Assistant" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Home<br/>Assistant</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/jellyfin" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/jellyfin.svg" alt="Jellyfin" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Jellyfin</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/jellyseerr" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/jellyseerr.svg" alt="Jellyseerr" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Jellyseerr</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/lidarr" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/lidarr.svg" alt="Lidarr" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Lidarr</p>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr><td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/linux-server-io" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/linuxserver-io.svg" alt="LinuxServer.io" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">LinuxServer.io</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/nextcloud" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/nextcloud.svg" alt="Nextcloud" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Nextcloud</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/npm" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/npm.svg" alt="NPM" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">NPM</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/ntfy" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/ntfy.svg" alt="ntfy" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">ntfy</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/nzbget" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/nzbget.svg" alt="NZBGet" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">NZBGet</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/open-media-vault" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/openmediavault.svg" alt="OpenMediaVault" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">OpenMediaVault</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/opnsense" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/opnsense.svg" alt="OPNsense" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">OPNsense</p>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr><td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/overseerr" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/overseerr.svg" alt="Overseerr" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Overseerr</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/pi-hole" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/pi-hole.svg" alt="Pi-hole" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Pi-hole</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/plex" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/plex.svg" alt="Plex" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Plex</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/prowlarr" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/prowlarr.svg" alt="Prowlarr" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Prowlarr</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/proxmox" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/proxmox.svg" alt="Proxmox" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Proxmox</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/q-bittorent" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/qbittorrent.svg" alt="qBittorrent" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">qBittorrent</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/quay" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/quay.png" alt="Quay" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Quay</p>
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr><td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/radarr" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/radarr.svg" alt="Radarr" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Radarr</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/readarr" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/readarr.svg" alt="Readarr" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Readarr</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/sabnzbd" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/sabnzbd.svg" alt="SABnzbd" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">SABnzbd</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/sonarr" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/sonarr.svg" alt="Sonarr" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Sonarr</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/tdarr" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/tdarr.png" alt="Tdarr" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Tdarr</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/transmission" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/svg/transmission.svg" alt="Transmission" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Transmission</p>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://homarr.dev/docs/integrations/unifi-controller" target="_blank" rel="noreferrer noopener">
|
||||
<img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons@master/png/unifi.png" alt="Unifi Controller" width="90" height="90" />
|
||||
<br/>
|
||||
<p align="center">Unifi<br/>Controller</p>
|
||||
</a>
|
||||
</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- AUTO_GENERATE_INTEGRATION_LIST_END -->
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
[](https://homarr.dev/docs/category/installation-1)
|
||||
|
||||
Since we are updating Homarr very frequently, we recommend reading our official installation guides:
|
||||

|
||||
|
||||
<h2>
|
||||
<a href="https://homarr.dev/docs/category/installation-1/">
|
||||
@@ -101,12 +319,15 @@ Since we are updating Homarr very frequently, we recommend reading our official
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
[](https://opencollective.com/homarr)
|
||||

|
||||
|
||||
<br/>
|
||||
|
||||
Homarr is a free to use open source project that is maintained by volunteers and developers from all over the world. We publish under the ``Apache License 2.0`` license which allows commercial usage. We invest multiple hours daily in to providing support, developing Homarr, integrating to third party software and more. We also pay for licensing and server hosting fees.
|
||||
Please consider to help us cover these costs to enable the future development of Homarr. Thank you!
|
||||
Homarr is a free-to-use open source project maintained by volunteers and developers from all over the world.
|
||||
We publish under the `Apache License 2.0` license which allows commercial usage.
|
||||
We invest multiple hours daily in providing support, developing Homarr, integrating to third party software and more.
|
||||
We also pay for licensing and server hosting fees.
|
||||
Please consider helping us cover these costs to enable the future development of Homarr. Thank you!
|
||||
|
||||
<h2>
|
||||
<a href="https://opencollective.com/homarr">
|
||||
@@ -117,9 +338,9 @@ Please consider to help us cover these costs to enable the future development of
|
||||
You can also support us by helping with [translating the entire project](https://homarr.dev/docs/community/translations) to as many languages as possible or contributing directly to the code or documentation. Please read our [Contribution Guidelines](/CONTRIBUTING.md). All contributions, regardless of their size or scope, are welcome and highly appreciated! Thank you ❤️
|
||||
|
||||
## Sponsors
|
||||
Thanks to your generous sponsors we can continue to build Homarr. Check them out for high quality and easy to use development tools.
|
||||
|
||||
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.
|
||||
|
||||
[](https://argos-ci.com?utm_source=%5Bhomarr%5D&utm_campaign=oss) \
|
||||
[](https://www.pikapods.com/pods?run=homarr-v1)
|
||||
|
||||
|
Before Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 33 KiB |
@@ -1,9 +1,10 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { createHomarrContainer } from "./shared/create-homarr-container";
|
||||
import { createRedisContainer } from "./shared/redis-container";
|
||||
|
||||
describe("Health checks", () => {
|
||||
test("ready and live should return 200 OK", async () => {
|
||||
test("ready and live should return 200 OK with normal image and no extra configuration", async () => {
|
||||
// Arrange
|
||||
const homarrContainer = await createHomarrContainer().start();
|
||||
|
||||
@@ -15,4 +16,31 @@ describe("Health checks", () => {
|
||||
expect(readyResponse.status).toBe(200);
|
||||
expect(liveResponse.status).toBe(200);
|
||||
}, 20_000);
|
||||
|
||||
test("ready and live should return 200 OK with external redis", async () => {
|
||||
// Arrange
|
||||
const redisContainer = await createRedisContainer().start();
|
||||
const homarrContainer = await createHomarrContainer({
|
||||
environment: {
|
||||
REDIS_IS_EXTERNAL: "true",
|
||||
REDIS_HOST: "host.docker.internal",
|
||||
REDIS_PORT: redisContainer.getMappedPort(6379).toString(),
|
||||
REDIS_PASSWORD: redisContainer.getPassword(),
|
||||
},
|
||||
}).start();
|
||||
|
||||
// Act
|
||||
const readyResponse = await fetch(`http://localhost:${homarrContainer.getMappedPort(7575)}/api/health/ready`);
|
||||
const liveResponse = await fetch(`http://localhost:${homarrContainer.getMappedPort(7575)}/api/health/live`);
|
||||
|
||||
// Assert
|
||||
expect(
|
||||
readyResponse.status,
|
||||
`Expected ready to return OK statusCode=${readyResponse.status} content=${await readyResponse.text()}`,
|
||||
).toBe(200);
|
||||
expect(
|
||||
liveResponse.status,
|
||||
`Expected live to return OK statusCode=${liveResponse.status} content=${await liveResponse.text()}`,
|
||||
).toBe(200);
|
||||
}, 20_000);
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
import { RedisContainer } from "@testcontainers/redis";
|
||||
|
||||
export const createRedisContainer = () => {
|
||||
return new RedisContainer("redis:latest").withPassword("homarr");
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "homarr",
|
||||
"version": "1.27.0",
|
||||
"version": "1.32.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "cross-env CI=true turbo build",
|
||||
@@ -27,7 +27,8 @@
|
||||
"test:e2e": "cross-env NODE_ENV=development CI=true vitest e2e",
|
||||
"test:ui": "cross-env NODE_ENV=development CI=true vitest --exclude e2e --ui --coverage.enabled",
|
||||
"typecheck": "turbo typecheck",
|
||||
"with-env": "dotenv -e .env --"
|
||||
"with-env": "dotenv -e .env --",
|
||||
"scripts:update-readme-integrations": "tsx ./scripts/update-integration-list.mts"
|
||||
},
|
||||
"prettier": "@homarr/prettier-config",
|
||||
"devDependencies": {
|
||||
@@ -38,24 +39,25 @@
|
||||
"@semantic-release/github": "^11.0.3",
|
||||
"@semantic-release/npm": "^12.0.2",
|
||||
"@semantic-release/release-notes-generator": "^14.0.3",
|
||||
"@turbo/gen": "^2.5.4",
|
||||
"@vitejs/plugin-react": "^4.6.0",
|
||||
"@testcontainers/redis": "^11.5.1",
|
||||
"@turbo/gen": "^2.5.5",
|
||||
"@vitejs/plugin-react": "^4.7.0",
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"@vitest/ui": "^3.2.4",
|
||||
"conventional-changelog-conventionalcommits": "^9.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"conventional-changelog-conventionalcommits": "^9.1.0",
|
||||
"cross-env": "^10.0.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"prettier": "^3.6.2",
|
||||
"semantic-release": "^24.2.6",
|
||||
"testcontainers": "^11.0.3",
|
||||
"turbo": "^2.5.4",
|
||||
"typescript": "^5.8.3",
|
||||
"semantic-release": "^24.2.7",
|
||||
"testcontainers": "^11.5.1",
|
||||
"turbo": "^2.5.5",
|
||||
"typescript": "^5.9.2",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"packageManager": "pnpm@10.12.4",
|
||||
"packageManager": "pnpm@10.14.0",
|
||||
"engines": {
|
||||
"node": ">=22.17.0"
|
||||
"node": ">=22.18.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
@@ -70,7 +72,7 @@
|
||||
"tree-sitter-json"
|
||||
],
|
||||
"overrides": {
|
||||
"proxmox-api>undici": "7.11.0"
|
||||
"proxmox-api>undici": "7.13.0"
|
||||
},
|
||||
"allowUnusedPatches": true,
|
||||
"ignoredBuiltDependencies": [
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"eslint": "^9.30.1",
|
||||
"typescript": "^5.8.3"
|
||||
"eslint": "^9.32.0",
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||
@@ -41,25 +41,25 @@
|
||||
"@homarr/server-settings": "workspace:^0.1.0",
|
||||
"@homarr/validation": "workspace:^0.1.0",
|
||||
"@kubernetes/client-node": "^1.3.0",
|
||||
"@tanstack/react-query": "^5.81.5",
|
||||
"@trpc/client": "^11.4.3",
|
||||
"@trpc/react-query": "^11.4.3",
|
||||
"@trpc/server": "^11.4.3",
|
||||
"@trpc/tanstack-react-query": "^11.4.3",
|
||||
"@tanstack/react-query": "^5.84.2",
|
||||
"@trpc/client": "^11.4.4",
|
||||
"@trpc/react-query": "^11.4.4",
|
||||
"@trpc/server": "^11.4.4",
|
||||
"@trpc/tanstack-react-query": "^11.4.4",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"next": "15.3.5",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"next": "15.4.6",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"superjson": "2.2.2",
|
||||
"trpc-to-openapi": "^2.3.2",
|
||||
"zod": "^3.25.74"
|
||||
"trpc-to-openapi": "^2.4.0",
|
||||
"zod": "^3.25.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"eslint": "^9.30.1",
|
||||
"eslint": "^9.32.0",
|
||||
"prettier": "^3.6.2",
|
||||
"typescript": "^5.8.3"
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { groupRouter } from "./router/group";
|
||||
import { homeRouter } from "./router/home";
|
||||
import { iconsRouter } from "./router/icons";
|
||||
import { importRouter } from "./router/import/import-router";
|
||||
import { infoRouter } from "./router/info";
|
||||
import { integrationRouter } from "./router/integration/integration-router";
|
||||
import { inviteRouter } from "./router/invite";
|
||||
import { kubernetesRouter } from "./router/kubernetes/router/kubernetes-router";
|
||||
@@ -47,6 +48,7 @@ export const appRouter = createTRPCRouter({
|
||||
media: mediaRouter,
|
||||
updateChecker: updateCheckerRouter,
|
||||
certificates: certificateRouter,
|
||||
info: infoRouter,
|
||||
});
|
||||
|
||||
// export type definition of API
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { createSaltAsync, hashPasswordAsync } from "@homarr/auth";
|
||||
import { createId } from "@homarr/common";
|
||||
import { generateSecureRandomToken } from "@homarr/common/server";
|
||||
import { createId, db, eq } from "@homarr/db";
|
||||
import { db, eq } from "@homarr/db";
|
||||
import { apiKeys } from "@homarr/db/schema";
|
||||
|
||||
import { createTRPCRouter, permissionRequiredProcedure } from "../trpc";
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import { asc, createId, eq, inArray, like } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
import { asc, eq, inArray, like } from "@homarr/db";
|
||||
import { apps } from "@homarr/db/schema";
|
||||
import { selectAppSchema } from "@homarr/db/validationSchemas";
|
||||
import { getIconForName } from "@homarr/icons";
|
||||
|
||||
@@ -3,9 +3,10 @@ import superjson from "superjson";
|
||||
import { z } from "zod";
|
||||
|
||||
import { constructBoardPermissions } from "@homarr/auth/shared";
|
||||
import { createId } from "@homarr/common";
|
||||
import type { DeviceType } from "@homarr/common/server";
|
||||
import type { Database, InferInsertModel, InferSelectModel, SQL } from "@homarr/db";
|
||||
import { and, asc, createId, eq, handleTransactionsAsync, inArray, isNull, like, not, or, sql } from "@homarr/db";
|
||||
import { and, asc, eq, handleTransactionsAsync, inArray, isNull, like, not, or, sql } from "@homarr/db";
|
||||
import { createDbInsertCollectionWithoutTransaction } from "@homarr/db/collection";
|
||||
import { getServerSettingByKeyAsync } from "@homarr/db/queries";
|
||||
import {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createId } from "@homarr/common";
|
||||
import type { Database } from "@homarr/db";
|
||||
import { and, createId, eq, handleTransactionsAsync, like, not } from "@homarr/db";
|
||||
import { and, eq, handleTransactionsAsync, like, not } from "@homarr/db";
|
||||
import { getMaxGroupPositionAsync } from "@homarr/db/queries";
|
||||
import { groupMembers, groupPermissions, groups } from "@homarr/db/schema";
|
||||
import { everyoneGroup } from "@homarr/definitions";
|
||||
@@ -276,12 +277,14 @@ export const groupRouter = createTRPCRouter({
|
||||
|
||||
await ctx.db.delete(groupPermissions).where(eq(groupPermissions.groupId, input.groupId));
|
||||
|
||||
await ctx.db.insert(groupPermissions).values(
|
||||
input.permissions.map((permission) => ({
|
||||
groupId: input.groupId,
|
||||
permission,
|
||||
})),
|
||||
);
|
||||
if (input.permissions.length > 0) {
|
||||
await ctx.db.insert(groupPermissions).values(
|
||||
input.permissions.map((permission) => ({
|
||||
groupId: input.groupId,
|
||||
permission,
|
||||
})),
|
||||
);
|
||||
}
|
||||
}),
|
||||
transferOwnership: permissionRequiredProcedure
|
||||
.requiresPermission("admin")
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import z from "zod";
|
||||
|
||||
import packageJson from "../../../../package.json";
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
|
||||
export const infoRouter = createTRPCRouter({
|
||||
getInfo: protectedProcedure
|
||||
.input(z.void())
|
||||
.output(z.object({ version: z.string() }))
|
||||
.meta({ openapi: { method: "GET", path: "/api/info", tags: ["info"] } })
|
||||
.query(() => {
|
||||
return {
|
||||
version: packageJson.version,
|
||||
};
|
||||
}),
|
||||
});
|
||||
@@ -1,10 +1,10 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import { objectEntries } from "@homarr/common";
|
||||
import { createId, objectEntries } from "@homarr/common";
|
||||
import { decryptSecret, encryptSecret } from "@homarr/common/server";
|
||||
import type { Database } from "@homarr/db";
|
||||
import { and, asc, createId, eq, handleTransactionsAsync, inArray, like } from "@homarr/db";
|
||||
import { and, asc, eq, handleTransactionsAsync, inArray, like } from "@homarr/db";
|
||||
import {
|
||||
groupMembers,
|
||||
groupPermissions,
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
getIconUrl,
|
||||
getIntegrationKindsByCategory,
|
||||
getPermissionsWithParents,
|
||||
integrationCategories,
|
||||
integrationDefs,
|
||||
integrationKinds,
|
||||
integrationSecretKindObject,
|
||||
@@ -129,6 +130,57 @@ export const integrationRouter = createTRPCRouter({
|
||||
integrationKinds.indexOf(integrationA.kind) - integrationKinds.indexOf(integrationB.kind),
|
||||
);
|
||||
}),
|
||||
allOfGivenCategory: publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
category: z.enum(integrationCategories),
|
||||
}),
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
const groupsOfCurrentUser = await ctx.db.query.groupMembers.findMany({
|
||||
where: eq(groupMembers.userId, ctx.session?.user.id ?? ""),
|
||||
});
|
||||
|
||||
const intergrationKinds = getIntegrationKindsByCategory(input.category);
|
||||
|
||||
const integrationsFromDb = await ctx.db.query.integrations.findMany({
|
||||
with: {
|
||||
userPermissions: {
|
||||
where: eq(integrationUserPermissions.userId, ctx.session?.user.id ?? ""),
|
||||
},
|
||||
groupPermissions: {
|
||||
where: inArray(
|
||||
integrationGroupPermissions.groupId,
|
||||
groupsOfCurrentUser.map((group) => group.groupId),
|
||||
),
|
||||
},
|
||||
},
|
||||
where: inArray(integrations.kind, intergrationKinds),
|
||||
});
|
||||
return integrationsFromDb
|
||||
.map((integration) => {
|
||||
const permissions = integration.userPermissions
|
||||
.map(({ permission }) => permission)
|
||||
.concat(integration.groupPermissions.map(({ permission }) => permission));
|
||||
|
||||
return {
|
||||
id: integration.id,
|
||||
name: integration.name,
|
||||
kind: integration.kind,
|
||||
url: integration.url,
|
||||
permissions: {
|
||||
hasUseAccess:
|
||||
permissions.includes("use") || permissions.includes("interact") || permissions.includes("full"),
|
||||
hasInteractAccess: permissions.includes("interact") || permissions.includes("full"),
|
||||
hasFullAccess: permissions.includes("full"),
|
||||
},
|
||||
};
|
||||
})
|
||||
.sort(
|
||||
(integrationA, integrationB) =>
|
||||
integrationKinds.indexOf(integrationA.kind) - integrationKinds.indexOf(integrationB.kind),
|
||||
);
|
||||
}),
|
||||
search: protectedProcedure
|
||||
.input(z.object({ query: z.string(), limit: z.number().min(1).max(100).default(10) }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
|
||||
@@ -2,7 +2,8 @@ import { randomBytes } from "crypto";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import { asc, createId, eq } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
import { asc, eq } from "@homarr/db";
|
||||
import { invites } from "@homarr/db/schema";
|
||||
import { selectInviteSchema } from "@homarr/db/validationSchemas";
|
||||
|
||||
|
||||
@@ -1,22 +1,33 @@
|
||||
import { observable } from "@trpc/server/observable";
|
||||
import z from "zod";
|
||||
|
||||
import { logger } from "@homarr/log";
|
||||
import { logLevels } from "@homarr/log/constants";
|
||||
import type { LoggerMessage } from "@homarr/redis";
|
||||
import { loggingChannel } from "@homarr/redis";
|
||||
import { zodEnumFromArray } from "@homarr/validation/enums";
|
||||
|
||||
import { createTRPCRouter, permissionRequiredProcedure } from "../trpc";
|
||||
|
||||
export const logRouter = createTRPCRouter({
|
||||
subscribe: permissionRequiredProcedure.requiresPermission("other-view-logs").subscription(() => {
|
||||
return observable<LoggerMessage>((emit) => {
|
||||
const unsubscribe = loggingChannel.subscribe((data) => {
|
||||
emit.next(data);
|
||||
});
|
||||
logger.info("A tRPC client has connected to the logging procedure");
|
||||
subscribe: permissionRequiredProcedure
|
||||
.requiresPermission("other-view-logs")
|
||||
.input(
|
||||
z.object({
|
||||
levels: z.array(zodEnumFromArray(logLevels)).default(["info"]),
|
||||
}),
|
||||
)
|
||||
.subscription(({ input }) => {
|
||||
return observable<LoggerMessage>((emit) => {
|
||||
const unsubscribe = loggingChannel.subscribe((data) => {
|
||||
if (!input.levels.includes(data.level)) return;
|
||||
emit.next(data);
|
||||
});
|
||||
logger.info("A tRPC client has connected to the logging procedure");
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
});
|
||||
}),
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
});
|
||||
}),
|
||||
});
|
||||
@@ -1,8 +1,9 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createId } from "@homarr/common";
|
||||
import type { InferInsertModel } from "@homarr/db";
|
||||
import { and, createId, desc, eq, like } from "@homarr/db";
|
||||
import { and, desc, eq, like } from "@homarr/db";
|
||||
import { iconRepositories, icons, medias } from "@homarr/db/schema";
|
||||
import { createLocalImageUrl, LOCAL_ICON_REPOSITORY_SLUG, mapMediaToIcon } from "@homarr/icons/local";
|
||||
import { byIdSchema, paginatedSchema } from "@homarr/validation/common";
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import { asc, createId, eq, like } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
import { asc, eq, like } from "@homarr/db";
|
||||
import { getServerSettingByKeyAsync, updateServerSettingByKeyAsync } from "@homarr/db/queries";
|
||||
import { searchEngines, users } from "@homarr/db/schema";
|
||||
import { createIntegrationAsync } from "@homarr/integrations";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import type { Session } from "@homarr/auth";
|
||||
import { createId } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
import { apps } from "@homarr/db/schema";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
import type { GroupPermissionKey } from "@homarr/definitions";
|
||||
|
||||
@@ -2,8 +2,9 @@ import SuperJSON from "superjson";
|
||||
import { describe, expect, it, test, vi } from "vitest";
|
||||
|
||||
import type { Session } from "@homarr/auth";
|
||||
import { createId } from "@homarr/common";
|
||||
import type { Database, InferInsertModel } from "@homarr/db";
|
||||
import { and, createId, eq, not } from "@homarr/db";
|
||||
import { and, eq, not } from "@homarr/db";
|
||||
import {
|
||||
boardGroupPermissions,
|
||||
boards,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import * as authShared from "@homarr/auth/shared";
|
||||
import { createId, eq } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
import { eq } from "@homarr/db";
|
||||
import { boards, users } from "@homarr/db/schema";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import type { Session } from "@homarr/auth";
|
||||
import * as env from "@homarr/auth/env";
|
||||
import { createId, eq } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
import { eq } from "@homarr/db";
|
||||
import { groupMembers, groupPermissions, groups, users } from "@homarr/db/schema";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
import type { GroupPermissionKey } from "@homarr/definitions";
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import * as authShared from "@homarr/auth/shared";
|
||||
import { createId, eq } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
import { eq } from "@homarr/db";
|
||||
import { integrations, users } from "@homarr/db/schema";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import type { Session } from "@homarr/auth";
|
||||
import { createId } from "@homarr/common";
|
||||
import { encryptSecret } from "@homarr/common/server";
|
||||
import { createId } from "@homarr/db";
|
||||
import { integrations, integrationSecrets } from "@homarr/db/schema";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
import type { GroupPermissionKey } from "@homarr/definitions";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import type { Session } from "@homarr/auth";
|
||||
import { createId } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
import { invites, users } from "@homarr/db/schema";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import SuperJSON from "superjson";
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import type { Session } from "@homarr/auth";
|
||||
import { createId } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
import { serverSettings } from "@homarr/db/schema";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
import { defaultServerSettings, defaultServerSettingsKeys } from "@homarr/server-settings";
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { describe, expect, it, test, vi } from "vitest";
|
||||
|
||||
import type { Session } from "@homarr/auth";
|
||||
import { createId } from "@homarr/common";
|
||||
import type { Database } from "@homarr/db";
|
||||
import { createId, eq } from "@homarr/db";
|
||||
import { eq } from "@homarr/db";
|
||||
import { invites, onboarding, users } from "@homarr/db/schema";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
import type { GroupPermissionKey, OnboardingStep } from "@homarr/definitions";
|
||||
|
||||
@@ -41,7 +41,7 @@ describe("ping should call sendPingRequestAsync with url and return result", ()
|
||||
deviceType: undefined,
|
||||
session: null,
|
||||
});
|
||||
spy.mockImplementation(() => Promise.resolve({ statusCode: 200 }));
|
||||
spy.mockImplementation(() => Promise.resolve({ statusCode: 200, durationMs: 123 }));
|
||||
|
||||
// Act
|
||||
const result = await caller.ping({ url });
|
||||
|
||||
@@ -2,8 +2,9 @@ import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createSaltAsync, hashPasswordAsync } from "@homarr/auth";
|
||||
import { createId } from "@homarr/common";
|
||||
import type { Database } from "@homarr/db";
|
||||
import { and, createId, eq, like } from "@homarr/db";
|
||||
import { and, eq, like } from "@homarr/db";
|
||||
import { getMaxGroupPositionAsync } from "@homarr/db/queries";
|
||||
import { boards, groupMembers, groupPermissions, groups, invites, users } from "@homarr/db/schema";
|
||||
import { selectUserSchema } from "@homarr/db/validationSchemas";
|
||||
|
||||
@@ -26,18 +26,20 @@ export const appRouter = createTRPCRouter({
|
||||
|
||||
const pingResult = await sendPingRequestAsync(input.url);
|
||||
|
||||
return observable<{ url: string; statusCode: number } | { url: string; error: string }>((emit) => {
|
||||
emit.next({ url: input.url, ...pingResult });
|
||||
const unsubscribe = pingChannel.subscribe((message) => {
|
||||
// Only emit if same url
|
||||
if (message.url !== input.url) return;
|
||||
emit.next(message);
|
||||
});
|
||||
return observable<{ url: string; statusCode: number; durationMs: number } | { url: string; error: string }>(
|
||||
(emit) => {
|
||||
emit.next({ url: input.url, ...pingResult });
|
||||
const unsubscribe = pingChannel.subscribe((message) => {
|
||||
// Only emit if same url
|
||||
if (message.url !== input.url) return;
|
||||
emit.next(message);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
void pingUrlChannel.removeAsync(input.url);
|
||||
};
|
||||
});
|
||||
return () => {
|
||||
unsubscribe();
|
||||
void pingUrlChannel.removeAsync(input.url);
|
||||
};
|
||||
},
|
||||
);
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,215 @@
|
||||
import { observable } from "@trpc/server/observable";
|
||||
|
||||
import type { Modify } from "@homarr/common/types";
|
||||
import type { Integration } from "@homarr/db/schema";
|
||||
import type { IntegrationKindByCategory } from "@homarr/definitions";
|
||||
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
||||
import type {
|
||||
FirewallCpuSummary,
|
||||
FirewallInterfacesSummary,
|
||||
FirewallMemorySummary,
|
||||
FirewallVersionSummary,
|
||||
} from "@homarr/integrations";
|
||||
import {
|
||||
firewallCpuRequestHandler,
|
||||
firewallInterfacesRequestHandler,
|
||||
firewallMemoryRequestHandler,
|
||||
firewallVersionRequestHandler,
|
||||
} from "@homarr/request-handler/firewall";
|
||||
|
||||
import { createManyIntegrationMiddleware } from "../../middlewares/integration";
|
||||
import { createTRPCRouter, publicProcedure } from "../../trpc";
|
||||
|
||||
export const firewallRouter = createTRPCRouter({
|
||||
getFirewallCpuStatus: publicProcedure
|
||||
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("firewall")))
|
||||
.query(async ({ ctx }) => {
|
||||
const results = await Promise.all(
|
||||
ctx.integrations.map(async (integration) => {
|
||||
const innerHandler = firewallCpuRequestHandler.handler(integration, {});
|
||||
const { data, timestamp } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false });
|
||||
|
||||
return {
|
||||
integration: {
|
||||
id: integration.id,
|
||||
name: integration.name,
|
||||
kind: integration.kind,
|
||||
updatedAt: timestamp,
|
||||
},
|
||||
summary: data,
|
||||
};
|
||||
}),
|
||||
);
|
||||
return results;
|
||||
}),
|
||||
subscribeFirewallCpuStatus: publicProcedure
|
||||
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("firewall")))
|
||||
.subscription(({ ctx }) => {
|
||||
return observable<{
|
||||
integration: Modify<Integration, { kind: IntegrationKindByCategory<"firewall"> }>;
|
||||
summary: FirewallCpuSummary;
|
||||
}>((emit) => {
|
||||
const unsubscribes: (() => void)[] = [];
|
||||
for (const integrationWithSecrets of ctx.integrations) {
|
||||
const { decryptedSecrets: _, ...integration } = integrationWithSecrets;
|
||||
const innerHandler = firewallCpuRequestHandler.handler(integrationWithSecrets, {});
|
||||
const unsubscribe = innerHandler.subscribe((summary) => {
|
||||
emit.next({
|
||||
integration,
|
||||
summary,
|
||||
});
|
||||
});
|
||||
unsubscribes.push(unsubscribe);
|
||||
}
|
||||
return () => {
|
||||
unsubscribes.forEach((unsubscribe) => {
|
||||
unsubscribe();
|
||||
});
|
||||
};
|
||||
});
|
||||
}),
|
||||
|
||||
getFirewallInterfacesStatus: publicProcedure
|
||||
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("firewall")))
|
||||
.query(async ({ ctx }) => {
|
||||
const results = await Promise.all(
|
||||
ctx.integrations.map(async (integration) => {
|
||||
const innerHandler = firewallInterfacesRequestHandler.handler(integration, {});
|
||||
const { data, timestamp } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false });
|
||||
|
||||
return {
|
||||
integration: {
|
||||
id: integration.id,
|
||||
name: integration.name,
|
||||
kind: integration.kind,
|
||||
updatedAt: timestamp,
|
||||
},
|
||||
summary: data,
|
||||
};
|
||||
}),
|
||||
);
|
||||
return results;
|
||||
}),
|
||||
subscribeFirewallInterfacesStatus: publicProcedure
|
||||
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("firewall")))
|
||||
.subscription(({ ctx }) => {
|
||||
return observable<{
|
||||
integration: Modify<Integration, { kind: IntegrationKindByCategory<"firewall"> }>;
|
||||
summary: FirewallInterfacesSummary[];
|
||||
}>((emit) => {
|
||||
const unsubscribes: (() => void)[] = [];
|
||||
for (const integrationWithSecrets of ctx.integrations) {
|
||||
const { decryptedSecrets: _, ...integration } = integrationWithSecrets;
|
||||
const innerHandler = firewallInterfacesRequestHandler.handler(integrationWithSecrets, {});
|
||||
const unsubscribe = innerHandler.subscribe((summary) => {
|
||||
emit.next({
|
||||
integration,
|
||||
summary,
|
||||
});
|
||||
});
|
||||
unsubscribes.push(unsubscribe);
|
||||
}
|
||||
return () => {
|
||||
unsubscribes.forEach((unsubscribe) => {
|
||||
unsubscribe();
|
||||
});
|
||||
};
|
||||
});
|
||||
}),
|
||||
|
||||
getFirewallVersionStatus: publicProcedure
|
||||
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("firewall")))
|
||||
.query(async ({ ctx }) => {
|
||||
const results = await Promise.all(
|
||||
ctx.integrations.map(async (integration) => {
|
||||
const innerHandler = firewallVersionRequestHandler.handler(integration, {});
|
||||
const { data, timestamp } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false });
|
||||
|
||||
return {
|
||||
integration: {
|
||||
id: integration.id,
|
||||
name: integration.name,
|
||||
kind: integration.kind,
|
||||
updatedAt: timestamp,
|
||||
},
|
||||
summary: data,
|
||||
};
|
||||
}),
|
||||
);
|
||||
return results;
|
||||
}),
|
||||
subscribeFirewallVersionStatus: publicProcedure
|
||||
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("firewall")))
|
||||
.subscription(({ ctx }) => {
|
||||
return observable<{
|
||||
integration: Modify<Integration, { kind: IntegrationKindByCategory<"firewall"> }>;
|
||||
summary: FirewallVersionSummary;
|
||||
}>((emit) => {
|
||||
const unsubscribes: (() => void)[] = [];
|
||||
for (const integrationWithSecrets of ctx.integrations) {
|
||||
const { decryptedSecrets: _, ...integration } = integrationWithSecrets;
|
||||
const innerHandler = firewallVersionRequestHandler.handler(integrationWithSecrets, {});
|
||||
const unsubscribe = innerHandler.subscribe((summary) => {
|
||||
emit.next({
|
||||
integration,
|
||||
summary,
|
||||
});
|
||||
});
|
||||
unsubscribes.push(unsubscribe);
|
||||
}
|
||||
return () => {
|
||||
unsubscribes.forEach((unsubscribe) => {
|
||||
unsubscribe();
|
||||
});
|
||||
};
|
||||
});
|
||||
}),
|
||||
|
||||
getFirewallMemoryStatus: publicProcedure
|
||||
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("firewall")))
|
||||
.query(async ({ ctx }) => {
|
||||
const results = await Promise.all(
|
||||
ctx.integrations.map(async (integration) => {
|
||||
const innerHandler = firewallMemoryRequestHandler.handler(integration, {});
|
||||
const { data, timestamp } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false });
|
||||
|
||||
return {
|
||||
integration: {
|
||||
id: integration.id,
|
||||
name: integration.name,
|
||||
kind: integration.kind,
|
||||
updatedAt: timestamp,
|
||||
},
|
||||
summary: data,
|
||||
};
|
||||
}),
|
||||
);
|
||||
return results;
|
||||
}),
|
||||
subscribeFirewallMemoryStatus: publicProcedure
|
||||
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("firewall")))
|
||||
.subscription(({ ctx }) => {
|
||||
return observable<{
|
||||
integration: Modify<Integration, { kind: IntegrationKindByCategory<"firewall"> }>;
|
||||
summary: FirewallMemorySummary;
|
||||
}>((emit) => {
|
||||
const unsubscribes: (() => void)[] = [];
|
||||
for (const integrationWithSecrets of ctx.integrations) {
|
||||
const { decryptedSecrets: _, ...integration } = integrationWithSecrets;
|
||||
const innerHandler = firewallMemoryRequestHandler.handler(integrationWithSecrets, {});
|
||||
const unsubscribe = innerHandler.subscribe((summary) => {
|
||||
emit.next({
|
||||
integration,
|
||||
summary,
|
||||
});
|
||||
});
|
||||
unsubscribes.push(unsubscribe);
|
||||
}
|
||||
return () => {
|
||||
unsubscribes.forEach((unsubscribe) => {
|
||||
unsubscribe();
|
||||
});
|
||||
};
|
||||
});
|
||||
}),
|
||||
});
|
||||
@@ -3,8 +3,10 @@ import { appRouter } from "./app";
|
||||
import { calendarRouter } from "./calendar";
|
||||
import { dnsHoleRouter } from "./dns-hole";
|
||||
import { downloadsRouter } from "./downloads";
|
||||
import { firewallRouter } from "./firewall";
|
||||
import { healthMonitoringRouter } from "./health-monitoring";
|
||||
import { indexerManagerRouter } from "./indexer-manager";
|
||||
import { mediaReleaseRouter } from "./media-release";
|
||||
import { mediaRequestsRouter } from "./media-requests";
|
||||
import { mediaServerRouter } from "./media-server";
|
||||
import { mediaTranscodingRouter } from "./media-transcoding";
|
||||
@@ -27,6 +29,7 @@ export const widgetRouter = createTRPCRouter({
|
||||
smartHome: smartHomeRouter,
|
||||
stockPrice: stockPriceRouter,
|
||||
mediaServer: mediaServerRouter,
|
||||
mediaRelease: mediaReleaseRouter,
|
||||
calendar: calendarRouter,
|
||||
downloads: downloadsRouter,
|
||||
mediaRequests: mediaRequestsRouter,
|
||||
@@ -38,5 +41,6 @@ export const widgetRouter = createTRPCRouter({
|
||||
options: optionsRouter,
|
||||
releases: releasesRouter,
|
||||
networkController: networkControllerRouter,
|
||||
firewall: firewallRouter,
|
||||
notifications: notificationsRouter,
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { observable } from "@trpc/server/observable";
|
||||
|
||||
import type { Modify } from "@homarr/common/types";
|
||||
import type { Integration } from "@homarr/db/schema";
|
||||
import type { IntegrationKindByCategory } from "@homarr/definitions";
|
||||
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
||||
import type { MediaRelease } from "@homarr/integrations/types";
|
||||
import { mediaReleaseRequestHandler } from "@homarr/request-handler/media-release";
|
||||
|
||||
import { createManyIntegrationMiddleware } from "../../middlewares/integration";
|
||||
import { createTRPCRouter, publicProcedure } from "../../trpc";
|
||||
|
||||
export const mediaReleaseRouter = createTRPCRouter({
|
||||
getMediaReleases: publicProcedure
|
||||
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("mediaRelease")))
|
||||
.query(async ({ ctx }) => {
|
||||
const results = await Promise.all(
|
||||
ctx.integrations.map(async (integration) => {
|
||||
const innerHandler = mediaReleaseRequestHandler.handler(integration, {});
|
||||
const { data, timestamp } = await innerHandler.getCachedOrUpdatedDataAsync({ forceUpdate: false });
|
||||
|
||||
return {
|
||||
integration: {
|
||||
id: integration.id,
|
||||
name: integration.name,
|
||||
kind: integration.kind,
|
||||
updatedAt: timestamp,
|
||||
},
|
||||
releases: data,
|
||||
};
|
||||
}),
|
||||
);
|
||||
return results.flatMap((result) =>
|
||||
result.releases.map((release) => ({
|
||||
...release,
|
||||
integration: result.integration,
|
||||
})),
|
||||
);
|
||||
}),
|
||||
|
||||
subscribeToReleases: publicProcedure
|
||||
.concat(createManyIntegrationMiddleware("query", ...getIntegrationKindsByCategory("mediaRelease")))
|
||||
.subscription(({ ctx }) => {
|
||||
return observable<{
|
||||
integration: Modify<Integration, { kind: IntegrationKindByCategory<"mediaRelease"> }>;
|
||||
releases: MediaRelease[];
|
||||
}>((emit) => {
|
||||
const unsubscribes: (() => void)[] = [];
|
||||
for (const integrationWithSecrets of ctx.integrations) {
|
||||
const { decryptedSecrets: _, ...integration } = integrationWithSecrets;
|
||||
const innerHandler = mediaReleaseRequestHandler.handler(integrationWithSecrets, {});
|
||||
const unsubscribe = innerHandler.subscribe((releases) => {
|
||||
emit.next({
|
||||
integration,
|
||||
releases,
|
||||
});
|
||||
});
|
||||
unsubscribes.push(unsubscribe);
|
||||
}
|
||||
return () => {
|
||||
unsubscribes.forEach((unsubscribe) => {
|
||||
unsubscribe();
|
||||
});
|
||||
};
|
||||
});
|
||||
}),
|
||||
});
|
||||
@@ -1,8 +1,10 @@
|
||||
import { escapeForRegEx } from "@tiptap/react";
|
||||
import { z } from "zod";
|
||||
|
||||
import { getIntegrationKindsByCategory } from "@homarr/definitions";
|
||||
import { releasesRequestHandler } from "@homarr/request-handler/releases";
|
||||
|
||||
import { createOneIntegrationMiddleware } from "../../middlewares/integration";
|
||||
import { createTRPCRouter, publicProcedure } from "../../trpc";
|
||||
|
||||
const formatVersionFilterRegex = (versionFilter: z.infer<typeof releaseVersionFilterSchema> | undefined) => {
|
||||
@@ -23,31 +25,31 @@ const releaseVersionFilterSchema = z.object({
|
||||
|
||||
export const releasesRouter = createTRPCRouter({
|
||||
getLatest: publicProcedure
|
||||
.concat(createOneIntegrationMiddleware("query", ...getIntegrationKindsByCategory("releasesProvider")))
|
||||
.input(
|
||||
z.object({
|
||||
repositories: z.array(
|
||||
z.object({
|
||||
providerKey: z.string(),
|
||||
id: z.string(),
|
||||
identifier: z.string(),
|
||||
versionFilter: releaseVersionFilterSchema.optional(),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const result = await Promise.all(
|
||||
.query(async ({ ctx, input }) => {
|
||||
return await Promise.all(
|
||||
input.repositories.map(async (repository) => {
|
||||
const innerHandler = releasesRequestHandler.handler({
|
||||
providerKey: repository.providerKey,
|
||||
const innerHandler = releasesRequestHandler.handler(ctx.integration, {
|
||||
id: repository.id,
|
||||
identifier: repository.identifier,
|
||||
versionRegex: formatVersionFilterRegex(repository.versionFilter),
|
||||
});
|
||||
|
||||
return await innerHandler.getCachedOrUpdatedDataAsync({
|
||||
forceUpdate: false,
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
return result;
|
||||
}),
|
||||
});
|
||||
@@ -1,8 +1,7 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { createBooleanSchema, createDurationSchema, createEnv } from "@homarr/core/infrastructure/env";
|
||||
import { supportedAuthProviders } from "@homarr/definitions";
|
||||
import { createEnv } from "@homarr/env";
|
||||
import { createBooleanSchema, createDurationSchema } from "@homarr/env/schemas";
|
||||
|
||||
const authProvidersSchema = z
|
||||
.string()
|
||||
|
||||
@@ -27,28 +27,28 @@
|
||||
"@auth/drizzle-adapter": "^1.10.0",
|
||||
"@homarr/certificates": "workspace:^0.1.0",
|
||||
"@homarr/common": "workspace:^0.1.0",
|
||||
"@homarr/core": "workspace:^0.1.0",
|
||||
"@homarr/db": "workspace:^0.1.0",
|
||||
"@homarr/definitions": "workspace:^0.1.0",
|
||||
"@homarr/env": "workspace:^0.1.0",
|
||||
"@homarr/log": "workspace:^0.1.0",
|
||||
"@homarr/validation": "workspace:^0.1.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
"cookies": "^0.9.1",
|
||||
"ldapts": "8.0.4",
|
||||
"next": "15.3.5",
|
||||
"ldapts": "8.0.9",
|
||||
"next": "15.4.6",
|
||||
"next-auth": "5.0.0-beta.29",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"zod": "^3.25.74"
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"zod": "^3.25.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"@types/bcrypt": "5.0.2",
|
||||
"@types/bcrypt": "6.0.0",
|
||||
"@types/cookies": "0.9.1",
|
||||
"eslint": "^9.30.1",
|
||||
"eslint": "^9.32.0",
|
||||
"prettier": "^3.6.2",
|
||||
"typescript": "^5.8.3"
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,14 @@
|
||||
import type { PropsWithChildren } from "react";
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
import type { IntegrationKind } from "@homarr/definitions";
|
||||
|
||||
interface IntegrationContextProps {
|
||||
integrations: {
|
||||
id: string;
|
||||
name: string;
|
||||
url: string;
|
||||
kind: string;
|
||||
kind: IntegrationKind;
|
||||
permissions: {
|
||||
hasFullAccess: boolean;
|
||||
hasInteractAccess: boolean;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { Session } from "next-auth";
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import { createId } from "@homarr/common";
|
||||
import type { InferInsertModel } from "@homarr/db";
|
||||
import { createId } from "@homarr/db";
|
||||
import { boardGroupPermissions, boards, boardUserPermissions, groupMembers, groups, users } from "@homarr/db/schema";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { CredentialsSignin } from "@auth/core/errors";
|
||||
import { z } from "zod";
|
||||
|
||||
import { extractErrorMessage } from "@homarr/common";
|
||||
import { createId, extractErrorMessage } from "@homarr/common";
|
||||
import type { Database, InferInsertModel } from "@homarr/db";
|
||||
import { and, createId, eq } from "@homarr/db";
|
||||
import { and, eq } from "@homarr/db";
|
||||
import { users } from "@homarr/db/schema";
|
||||
import { logger } from "@homarr/log";
|
||||
import type { userSignInSchema } from "@homarr/validation/user";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
import { createId } from "@homarr/db";
|
||||
import { createId } from "@homarr/common";
|
||||
import { users } from "@homarr/db/schema";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { CredentialsSignin } from "@auth/core/errors";
|
||||
import { describe, expect, test, vi } from "vitest";
|
||||
|
||||
import { createId } from "@homarr/common";
|
||||
import type { Database } from "@homarr/db";
|
||||
import { and, createId, eq } from "@homarr/db";
|
||||
import { and, eq } from "@homarr/db";
|
||||
import { groups, users } from "@homarr/db/schema";
|
||||
import { createDb } from "@homarr/db/test";
|
||||
|
||||
|
||||
@@ -25,14 +25,14 @@
|
||||
"prettier": "@homarr/prettier-config",
|
||||
"dependencies": {
|
||||
"@homarr/api": "workspace:^0.1.0",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0"
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"eslint": "^9.30.1",
|
||||
"typescript": "^5.8.3"
|
||||
"eslint": "^9.32.0",
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,13 @@
|
||||
"dependencies": {
|
||||
"@homarr/common": "workspace:^0.1.0",
|
||||
"@homarr/db": "workspace:^0.1.0",
|
||||
"undici": "7.11.0"
|
||||
"undici": "7.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"eslint": "^9.30.1",
|
||||
"typescript": "^5.8.3"
|
||||
"eslint": "^9.32.0",
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { Agent as HttpsAgent } from "node:https";
|
||||
import path from "node:path";
|
||||
import { checkServerIdentity, rootCertificates } from "node:tls";
|
||||
import axios from "axios";
|
||||
import type { RequestInfo, RequestInit, Response } from "undici";
|
||||
import { fetch } from "undici";
|
||||
|
||||
import { env } from "@homarr/common/env";
|
||||
@@ -15,9 +16,8 @@ import { db } from "@homarr/db";
|
||||
import type { trustedCertificateHostnames } from "@homarr/db/schema";
|
||||
|
||||
const getCertificateFolder = () => {
|
||||
return env.NODE_ENV === "production"
|
||||
? path.join("/appdata", "trusted-certificates")
|
||||
: process.env.LOCAL_CERTIFICATE_PATH;
|
||||
if (env.NODE_ENV !== "production") return process.env.LOCAL_CERTIFICATE_PATH;
|
||||
return process.env.LOCAL_CERTIFICATE_PATH ?? path.join("/appdata", "trusted-certificates");
|
||||
};
|
||||
|
||||
export const loadCustomRootCertificatesAsync = async () => {
|
||||
@@ -132,8 +132,8 @@ export const createAxiosCertificateInstanceAsync = async (
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchWithTrustedCertificatesAsync: typeof fetch = async (url, options) => {
|
||||
const agent = await createCertificateAgentAsync();
|
||||
export const fetchWithTrustedCertificatesAsync = async (url: RequestInfo, options?: RequestInit): Promise<Response> => {
|
||||
const agent = await createCertificateAgentAsync(undefined);
|
||||
return fetch(url, {
|
||||
...options,
|
||||
dispatcher: agent,
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
"@homarr/common": "workspace:^0.1.0",
|
||||
"@homarr/db": "workspace:^0.1.0",
|
||||
"@homarr/validation": "workspace:^0.1.0",
|
||||
"dotenv": "^17.0.1"
|
||||
"dotenv": "^17.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"esbuild": "^0.25.5",
|
||||
"eslint": "^9.30.1",
|
||||
"typescript": "^5.8.3"
|
||||
"esbuild": "^0.25.8",
|
||||
"eslint": "^9.32.0",
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import { command, string } from "@drizzle-team/brocli";
|
||||
|
||||
import { createSaltAsync, hashPasswordAsync } from "@homarr/auth";
|
||||
import { createId } from "@homarr/common";
|
||||
import { generateSecureRandomToken } from "@homarr/common/server";
|
||||
import { and, count, createId, db, eq } from "@homarr/db";
|
||||
import { and, count, db, eq } from "@homarr/db";
|
||||
import { getMaxGroupPositionAsync } from "@homarr/db/queries";
|
||||
import { groupMembers, groupPermissions, groups, users } from "@homarr/db/schema";
|
||||
import { usernameSchema } from "@homarr/validation/user";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { randomBytes } from "crypto";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createEnv } from "@homarr/env";
|
||||
import { createEnv } from "@homarr/core/infrastructure/env";
|
||||
|
||||
const errorSuffix = `, please generate a 64 character secret in hex format or use the following: "${randomBytes(32).toString("hex")}"`;
|
||||
|
||||
|
||||
@@ -27,21 +27,22 @@
|
||||
},
|
||||
"prettier": "@homarr/prettier-config",
|
||||
"dependencies": {
|
||||
"@homarr/env": "workspace:^0.1.0",
|
||||
"@homarr/core": "workspace:^0.1.0",
|
||||
"@homarr/log": "workspace:^0.1.0",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"dayjs": "^1.11.13",
|
||||
"next": "15.3.5",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"undici": "7.11.0",
|
||||
"zod": "^3.25.74",
|
||||
"zod-validation-error": "^3.5.2"
|
||||
"next": "15.4.6",
|
||||
"react": "19.1.1",
|
||||
"react-dom": "19.1.1",
|
||||
"undici": "7.13.0",
|
||||
"zod": "^3.25.76",
|
||||
"zod-validation-error": "^3.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"eslint": "^9.30.1",
|
||||
"typescript": "^5.8.3"
|
||||
"eslint": "^9.32.0",
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||