diff --git a/apps/docs/docs/advanced/command-line/img/334116069-e7ec4726-3df7-4dc6-a3e0-b745e7eef17f.png b/apps/docs/docs/advanced/command-line/img/334116069-e7ec4726-3df7-4dc6-a3e0-b745e7eef17f.png deleted file mode 100644 index 79a29d1c6..000000000 Binary files a/apps/docs/docs/advanced/command-line/img/334116069-e7ec4726-3df7-4dc6-a3e0-b745e7eef17f.png and /dev/null differ diff --git a/apps/docs/docs/advanced/command-line/img/334116205-aa09ce40-0701-4f7d-b9f9-b431b9d207c5.png b/apps/docs/docs/advanced/command-line/img/334116205-aa09ce40-0701-4f7d-b9f9-b431b9d207c5.png deleted file mode 100644 index 881115da8..000000000 Binary files a/apps/docs/docs/advanced/command-line/img/334116205-aa09ce40-0701-4f7d-b9f9-b431b9d207c5.png and /dev/null differ diff --git a/apps/docs/docs/advanced/command-line/img/334116303-714b5e07-b9de-4ec0-a2bc-def7ee38750f.png b/apps/docs/docs/advanced/command-line/img/334116303-714b5e07-b9de-4ec0-a2bc-def7ee38750f.png deleted file mode 100644 index 9225083fb..000000000 Binary files a/apps/docs/docs/advanced/command-line/img/334116303-714b5e07-b9de-4ec0-a2bc-def7ee38750f.png and /dev/null differ diff --git a/apps/docs/docs/advanced/command-line/img/334116411-df1482f9-3aa9-4686-b77f-e0dca09e60b2.png b/apps/docs/docs/advanced/command-line/img/334116411-df1482f9-3aa9-4686-b77f-e0dca09e60b2.png deleted file mode 100644 index 3ab3823eb..000000000 Binary files a/apps/docs/docs/advanced/command-line/img/334116411-df1482f9-3aa9-4686-b77f-e0dca09e60b2.png and /dev/null differ diff --git a/apps/docs/docs/advanced/command-line/img/334116518-e1ddb515-99c7-4159-81bf-76e889d1e808.png b/apps/docs/docs/advanced/command-line/img/334116518-e1ddb515-99c7-4159-81bf-76e889d1e808.png deleted file mode 100644 index f998982a6..000000000 Binary files a/apps/docs/docs/advanced/command-line/img/334116518-e1ddb515-99c7-4159-81bf-76e889d1e808.png and /dev/null differ diff --git a/apps/docs/docs/advanced/command-line/img/334116642-08c4f204-5cd0-4e4e-a785-0142e1b279ca.png b/apps/docs/docs/advanced/command-line/img/334116642-08c4f204-5cd0-4e4e-a785-0142e1b279ca.png deleted file mode 100644 index 748be0664..000000000 Binary files a/apps/docs/docs/advanced/command-line/img/334116642-08c4f204-5cd0-4e4e-a785-0142e1b279ca.png and /dev/null differ diff --git a/apps/docs/docs/advanced/command-line/img/homarr-dev-cli.png b/apps/docs/docs/advanced/command-line/img/homarr-dev-cli.png new file mode 100644 index 000000000..e23c952aa Binary files /dev/null and b/apps/docs/docs/advanced/command-line/img/homarr-dev-cli.png differ diff --git a/apps/docs/docs/advanced/command-line/index.mdx b/apps/docs/docs/advanced/command-line/index.mdx index 0e77162a2..f04a01799 100644 --- a/apps/docs/docs/advanced/command-line/index.mdx +++ b/apps/docs/docs/advanced/command-line/index.mdx @@ -1,48 +1,41 @@ # Command line interface -The Homarr image ships with a built-in recovery tool. This can be useful, if you do not have access to Homarr or if something is not working. -Please note that the CLI is an _emergency tool_, not an API tool. +The Homarr image includes a recovery CLI for operations that cannot be completed in the web interface. It is not an +application API; use the [API](/docs/management/api) or [MCP endpoint](/docs/management/mcp) for automation. -:::caution +Back up the database and stop Homarr before running a command that changes data. -Using the recovery CLi tool can cause problems when requests are being sent to Homarr while the tool is running. \ -You should also create a backup of the database, in case you break something. +## Run the recovery CLI -::: +Open a shell in the container, then pass a command to `homarr`: -## Execute CLI with Docker +```sh +docker exec -it /bin/bash +homarr +``` -1. Execute `docker ps | grep homarr` on the root system with Docker to find the container ID of your Homarr container. -2. Run `docker exec -it /bin/bash homarr `. \ - Replace `` with your container ID from step 1. \ - Replace `` with the command you want to execute (see sub-pages). +In QNAP Container Station, open the Homarr container's **Execute** action and select `/bin/bash`. -## Execute CLI with QNAP - -1. Open Container Station in the QNAP Web Interface ![](img/334116069-e7ec4726-3df7-4dc6-a3e0-b745e7eef17f.png) -2. Select Containers in the menu bar on the left ![](img/334116205-aa09ce40-0701-4f7d-b9f9-b431b9d207c5.png) -3. Select your Homarr Container ![](img/334116303-714b5e07-b9de-4ec0-a2bc-def7ee38750f.png) -4. Click "Execute" in the top right of the Window. ![](img/334116411-df1482f9-3aa9-4686-b77f-e0dca09e60b2.png) -5. Select /bin/bash and click Execute ![](img/334116518-e1ddb515-99c7-4159-81bf-76e889d1e808.png) -6. Run the Homarr command and press enter (eg. homarr reset-owner-password) ![](img/334116642-08c4f204-5cd0-4e4e-a785-0142e1b279ca.png) +See the pages in this section for available commands. ## Build a local branch harness -The host-side operations CLI can build the current checkout and run it as a named, browser-ready Docker harness. This is separate from the recovery CLI described above and does not open the interactive developer TUI. +The repository's host-side CLI can build the current checkout and run it as a named Docker harness: + +![Homarr developer CLI showing pull requests, local images, and PR CI status](./img/homarr-dev-cli.png) ```sh pnpm cli harness setup feature-board ``` -The command builds `homarr:feature-board`, starts a container with a persistent data volume, enables demo mode, and keeps demo mutations writable (`DEMO_READ_ONLY=false`). Docker assigns a free host port by default; use the URL printed by the command or query it later: - -The demo board includes every widget kind. Integration-backed widgets use the bundled mock integration; media widgets use public stock assets. +This creates `homarr:feature-board`, starts it with persistent demo data, and prints the assigned URL. Query the port +again with: ```sh pnpm cli harness port feature-board ``` -Pass environment overrides by repeating `--env`: +Pass environment overrides with repeated `--env` options: ```sh pnpm cli harness setup feature-board \ @@ -50,4 +43,4 @@ pnpm cli harness setup feature-board \ --env FEATURE_FLAG=true ``` -Other commands are `harness build `, `harness run `, and `harness stop `. Use the returned URL with a browser automation harness for feature validation; do not assume the host port is `7575`. +Related commands are `harness build `, `harness run `, and `harness stop `. diff --git a/apps/docs/docs/advanced/development/getting-started.mdx b/apps/docs/docs/advanced/development/getting-started.mdx index a75ccf403..1ab74a197 100644 --- a/apps/docs/docs/advanced/development/getting-started.mdx +++ b/apps/docs/docs/advanced/development/getting-started.mdx @@ -58,7 +58,7 @@ Use `pnpm docker:dev:up` instead when you only need Redis in the background. Run default data; use `pnpm db:seed` to seed it explicitly later. Workshop contributors can set up PocketBase and Docusaurus with the dedicated -[Workshop development guide](../../workshop/development). +[Workshop development guide](./workshop). ### Useful commands diff --git a/apps/docs/docs/advanced/development/workshop-operator.mdx b/apps/docs/docs/advanced/development/workshop-operator.mdx new file mode 100644 index 000000000..502a4a7f5 --- /dev/null +++ b/apps/docs/docs/advanced/development/workshop-operator.mdx @@ -0,0 +1,67 @@ +--- +title: Workshop operator guide +sidebar_label: Operator guide +sidebar_position: 3 +tags: + - Workshop + - Deployment + - Environment variables + - PocketBase +--- + +# Workshop operator guide + +Workshop uses PocketBase. The production image serves the Workshop website and API from one origin and stores state in +`/pb_data`. + +## Environment variables + +| Variable | Purpose | Default | +| -------------------------------------- | -------------------------------------------- | ------------------------------ | +| `HOMARR_WEBSITE_URL` | Documentation/site base used by Homarr links | `https://homarr.dev` | +| `WORKSHOP_API_URL` | PocketBase API used by Homarr and docs | `HOMARR_WEBSITE_URL` | +| `WORKSHOP_WEB_URL` | Public Workshop URL | `HOMARR_WEBSITE_URL/workshop` | +| `WORKSHOP_PUBLIC_ORIGIN` | PocketBase-generated links and email | Required in production | +| `PB_ALLOWED_ORIGINS` | Allowed browser origins | `*` | +| `GITHUB_CLIENT_ID` | GitHub OAuth application ID | — | +| `GITHUB_CLIENT_SECRET` | GitHub OAuth application secret | — | +| `OPENROUTER_API_KEY` | Enables the Homarr Assistant provider | Provider disabled when empty | +| `HOMARR_AI_DAILY_REQUEST_LIMIT` | Per-user daily request allowance | `50` | +| `HOMARR_AI_GLOBAL_DAILY_REQUEST_LIMIT` | Shared daily request ceiling | `10000` | +| `HOMARR_AI_OPENROUTER_BASE_URL` | OpenRouter-compatible upstream | `https://openrouter.ai/api/v1` | +| `HOMARR_AI_OPENROUTER_MODEL` | Upstream model behind `homarr/model` | Selected by the Homarr team | + +Public URL variables accept HTTP(S) origins without embedded credentials, query strings, or fragments. Restart the +container after changing runtime configuration. + +## Authentication and email + +Configure both GitHub OAuth variables and use `https:///api/oauth2-redirect` as the callback. Supplying +only one OAuth variable is a startup error. Configure SMTP for comment, report, and removal notifications. + +For the central community, `PB_ALLOWED_ORIGINS=*` permits requests from self-hosted Homarr origins. A private deployment +can use a comma-separated allowlist. + +## Homarr provider + +`OPENROUTER_API_KEY` enables the [Homarr provider](/docs/workshop/homarr-provider). The Workshop server chooses the upstream model and +enforces per-user and global daily limits. It requests zero-data-retention routing, disables data-collecting providers, +and does not retain prompts or responses. + +Keep an OpenRouter account-level credit limit as the monetary backstop; request limits are not cost limits. + +## Deployment + +The v2 image is `ghcr.io/homarr-labs/workshop:v2`; immutable `sha-` tags are preferable for promotion. The +service listens on port 8090. + +When using a reverse proxy, forward the complete hostname, including `/api`, `/_/`, and +`/workshop-runtime-config.js`. Use a dedicated hostname when Homarr already occupies the intended origin. + +Verify `/api/health`, the Workshop page, a public listing request, GitHub sign-in, and one installation after deployment. + +## Backup and restore + +Stop writes and copy `/pb_data` for a consistent backup. A restore replaces the selected PocketBase data directory, so +preserve the current volume and verify that the backup contains `data.db` first. Rehearse the restore outside production +and verify sign-in and one installation afterward. diff --git a/apps/docs/docs/advanced/development/workshop.mdx b/apps/docs/docs/advanced/development/workshop.mdx new file mode 100644 index 000000000..34ecde97e --- /dev/null +++ b/apps/docs/docs/advanced/development/workshop.mdx @@ -0,0 +1,41 @@ +--- +title: Workshop development +sidebar_position: 4 +tags: + - Workshop + - Developer + - Docusaurus + - PocketBase +--- + +# Workshop development + +See the [main development guide](./getting-started) for repository prerequisites. + +Start PocketBase: + +```sh +cp apps/workshop/.env.example apps/workshop/.env +docker compose --env-file apps/workshop/.env -f apps/workshop/docker-compose.yml up --build workshop +``` + +Start Docusaurus in another terminal: + +```sh +WORKSHOP_API_URL=http://127.0.0.1:8090 pnpm dev:docs +``` + +PocketBase runs at `http://127.0.0.1:8090`; create the first superuser under `/_/`. Workshop is available at +`http://127.0.0.1:3003/workshop`. + +To connect a local Homarr instance, set: + +```dotenv +HOMARR_WEBSITE_URL=http://127.0.0.1:3003 +WORKSHOP_API_URL=http://127.0.0.1:8090 +WORKSHOP_WEB_URL=http://127.0.0.1:3003/workshop +``` + +Restart the affected development process after changing these variables. See +[`apps/workshop/README.md`](https://github.com/homarr-labs/homarr/blob/HEAD/apps/workshop/README.md) for OAuth, +moderation, tests, and service maintenance. diff --git a/apps/docs/docs/advanced/environment-variables/index.mdx b/apps/docs/docs/advanced/environment-variables/index.mdx index f3311ed82..364545e27 100644 --- a/apps/docs/docs/advanced/environment-variables/index.mdx +++ b/apps/docs/docs/advanced/environment-variables/index.mdx @@ -38,7 +38,7 @@ Using the `PUID` and `PGID` will require you to set the correct permissions on t | `WORKSHOP_WEB_URL` | Public Workshop website used by links in Homarr, Custom Widgets, onboarding, and assistant context. | HTTP(S) URL | `HOMARR_WEBSITE_URL/workshop` | Workshop service operators can find its server-only configuration in the -[Workshop operator guide](../../workshop/operator#environment-variables). +[Workshop operator guide](/docs/advanced/development/workshop-operator#environment-variables). ### Workshop service diff --git a/apps/docs/docs/advanced/proxy/index.mdx b/apps/docs/docs/advanced/proxy/index.mdx index fbe33bfa4..b1e15a6fb 100644 --- a/apps/docs/docs/advanced/proxy/index.mdx +++ b/apps/docs/docs/advanced/proxy/index.mdx @@ -143,7 +143,7 @@ networks: ``` :::important -Homarr needs to be on the same network so you will need to add the following property to your homarr install: +Homarr and Caddy must share the same Docker network: ```yaml homarr: diff --git a/apps/docs/docs/advanced/styling/index.mdx b/apps/docs/docs/advanced/styling/index.mdx index 705a3eccd..2a95b08b6 100644 --- a/apps/docs/docs/advanced/styling/index.mdx +++ b/apps/docs/docs/advanced/styling/index.mdx @@ -1,105 +1,37 @@ # Styling -:::tip +Homarr uses Mantine and supports custom CSS at two scopes: -This page is directed at more experienced users with knowledge about CSS and browsers. -We recommend you to [look into the board customizations instead](/docs/management/boards#appearance), -if you do not have experience with writing custom styles or CSS. +- **Global:** **Management → Settings → Instance branding → Custom CSS**. +- **Board:** **Board settings → Custom CSS**. Board CSS loads after the global stylesheet and can override it. -::: +Both editors accept direct CSS and Workshop imports. :::warning -Our support specifically excludes custom CSS, and we will not help you to write CSS. -However, we may help you by adding new CSS classes if required. +Custom CSS can break after updates and is not an authorization boundary. Hidden controls remain accessible to users who +have permission to use them. ::: -Homarr uses https://mantine.dev/ under the hood. You can change the look & feel of Homarr -using custom CSS, that extends or overwrites the styles from Mantine. +## Target elements -## Getting into CSS +Use browser developer tools to inspect the element and test a selector. Prefer stable semantic or Mantine class names; +avoid generated classes such as `mantine-Card-x2fske`, which change between builds. -If you don't have any experience with CSS, -we strongly recommend you to go through the courses here: https://www.w3schools.com/css/. -Due to the infinite scenarios and setups possible with custom CSS, -our support team will not provide any support with your own written CSS. +To target one widget, add a custom class under **Edit item → Advanced options** and use that class in the board CSS. -## Limitations and dangers +Use `!important` only when the existing cascade requires it. -When using custom CSS, you can break the page or certain functionalities. -Although CSS can improve the design & feel of the page, it **cannot do any of the following**: +## Theme variables -- Implement new features, widgets or integrations -- Securely hide elements you don't want users to interact / have permission to -- Completely revamp the design of the page, only smaller changes are possible - -Here are some dangers of using custom CSS: - -- Updates may contain breaking changes in the structure, built-in styling or how styling is processed. Therefore, - custom CSS may break unexpectedly without any warning -- Custom CSS may make certain elements invisible or not possible to click / interact with -- Custom CSS could make readability and accessibility worse for impaired people - -## How to inspect the page - -When styling the page, you can use the `Inspector` to inspect elements on the page and try out styles. -This may vary depending on your browser and operating system, but the workflow usually goes like this: - -- Open the Homarr page -- Press `Ctrl` + `Shift` + `I` at the same time. - Alternatively, right-click on the page and choose `Inspect` or `Inspect element`. -- Open the tab `Elements` if it isn't open yet. -- Search the element you want to change in the DOM tree or use the element picker (usually at the top left) - to select it by clicking on the page. -- Experiment by changing the CSS code on the right side - -When writing custom CSS, it is important to also remember or create a selector, which tells the browser -which element to apply the styles to. If you accidentally broke something or want to revert your changes in the inspector, -simply reload the page. - -## Using Homarr's classes - -Homarr's elements will already have a lot of classes and styles pre-applied. -You can reuse those classes to apply additional styles or overwrite them. -When overwriting, remember to add the `!important` flag to your CSS property to tell the browser to use our instruction instead. - -Classes with random number suffixes, such as `mantine-Card-x2fske`, should be avoided, since those are dynamic -CSS classes that will change with every build. This means, every time you update Homarr, -your styles will no longer apply to them - -## Defining custom classes for widgets - -If you want to apply the styles only for one widget, you can define custom class names only for that widget. -To do that, enter edit mode on your board, click the three dots of your widget, click `Edit item` and click `Advanced options`. -Then, you can enter as many custom classes as you'd like: - -![](./img/widget-custom-classes.png) - -To save them, click `Save changes` on both modals and exit edit mode. - -## Where to enter custom CSS - -After you wrote your custom CSS, it is time to permanently save it, so you don't need to use the inspector anymore. -To do this, enter the board settings: - -![](./img/enter-board-settings.png) - -Administrators can add instance-wide CSS under **Management → Settings → Branding → Custom CSS**. Enter CSS directly -or import a community theme from the Workshop, then save the server settings to apply it to every page. - -For board-specific styling, scroll to the **Custom CSS** section on the board settings page. Enter your CSS there and -save the board settings to apply it to that board. Board CSS is loaded after the global stylesheet and can override it. - -![](./img/custom-css-setting.png) - -## Using variables - -You can also change the values of the theme variables, which are located here: https://mantine.dev/styles/css-variables-list/. -To do this, see the following example CSS: +Mantine exposes [CSS variables](https://mantine.dev/styles/css-variables-list/) that can be overridden globally or per +board: ```css :root { --mantine-primary-color-filled: #ffbb00; } ``` + +CSS changes presentation only; use widgets, integrations, permissions, or application code for behavior. diff --git a/apps/docs/docs/community/donate.mdx b/apps/docs/docs/community/donate.mdx index 3651a2a7b..b139307c3 100644 --- a/apps/docs/docs/community/donate.mdx +++ b/apps/docs/docs/community/donate.mdx @@ -8,22 +8,7 @@ tags: # Donate -## Why to donate +Donations fund Homarr's development infrastructure and community services. -Our team of 4 developers is working on Homarr in their free time. -Homarr has become a big part of our daily things we work on - and therefore we invest a lot of time into maintaining Homarr, -providing support and implementing new features. -We also incur monetary costs while developing Homarr for the tools that we need. -A few examples include: - -- Renting for a Cloud VPS for our cloud services (status page, monitoring, email, analytics, [demo instance](https://demo.homarr.dev/), ...) -- Paying for (IDE-) licenses - -Using a donation, you help us to cover these expenses and enable the development of Homarr. -Homarr is completely free to use. We'd highly appreciate if you consider donating, especially if you use Homarr in a commercial environment. - -## Where to donate - -We accept donations on our official [OpenCollective](https://opencollective.com/homarr). -You may also sponsor us directly by providing a useful service / product to us other means. -You can get into contact with us [here](/docs/community/get-in-touch). +Support the project through [OpenCollective](https://opencollective.com/homarr). For sponsorships or donated services, +use the private contact listed on [Get in touch](/docs/community/get-in-touch). diff --git a/apps/docs/docs/community/faq.mdx b/apps/docs/docs/community/faq.mdx index 19f2cd0e0..2beeaae7e 100644 --- a/apps/docs/docs/community/faq.mdx +++ b/apps/docs/docs/community/faq.mdx @@ -5,106 +5,46 @@ tags: - Help --- -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; +### Can Homarr run on a Raspberry Pi? -### Can I install Homarr on a Raspberry Pi? +Yes, when the device uses a supported `linux/arm64` operating system. `linux/arm/v7` is not supported. See +[Prerequisites](/docs/getting-started). -Yes, Homarr is compatible with the architecture of the Raspberry Pi. Have a look in our installation guide on how to do so. +### Can I use custom app icons? -### I have a suggestion / idea for improvement or want to report a bug +Yes. Use a direct image URL, one of Homarr's icon sources, or upload an image. See [Icons](/docs/advanced/icons). -You can report issues, suggestions, or ideas for improvements here. +### Can I create widgets? -### Can I use my own custom icons for apps? +Yes. [Custom Widgets](/docs/management/custom-widgets) use server-side API requests and safe JSX. They can be written in +the workbench or created with an MCP-connected agent. -Yes, check out our guide on how to add your custom icons. +### Can Homarr be exposed to the internet? -### Some of my online icons are not working (anymore) +Homarr supports authenticated and public deployments. Terminate HTTPS at a reverse proxy, keep Homarr updated, and grant +public board access only when anonymous viewing is intended. See [Board access control](/docs/management/boards#access-control) +and [Single sign-on](/docs/advanced/single-sign-on). -It seems the `cdn.jsdelivr.net` database of icon sometimes appear in the lists for DNS-Holes (PiHole, AdGuard Home...).
-So make sure to manually whitelist this address. +### Where are the logs? -### Can I add my own widgets? Do I need programming skills? +Use **Management → Tools → Logs** for retained and live application logs. Container startup failures and older events are +available through the deployment platform, for example `docker container logs homarr`. -Yes. A [Custom Widget](/docs/management/custom-widgets) can read a public or private HTTP API. +Use the browser developer console only for client-side failures. Review logs before sharing them because URLs and other +deployment details may be present. -It can show responsive Mantine JSX. It can also use widget options and actions with board permission checks. +### Why can Homarr not reach a service behind Gluetun? -Custom JSX v2 is the only Custom Widget format. Write the JSON and JSX in the workbench. +Gluetun's firewall blocks traffic that is not explicitly allowed. Configure its +[`FIREWALL_OUTBOUND_SUBNETS`](https://github.com/qdm12/gluetun-wiki/blob/main/setup/options/firewall.md) for the relevant +LAN or Docker subnet, and use an address reachable from the Homarr container. -You can also use the AI copy prompt. An MCP agent can validate and preview a definition before it saves the definition. +### Where do I report a bug or request a feature? -The workbench reads a pasted AI response. It shows request capabilities and redacted diagnostics. +Use the [GitHub issue templates](https://github.com/homarr-labs/homarr/issues/new/choose). For community support, see +[Get in touch](/docs/community/get-in-touch). -A template cannot import packages or run arbitrary JavaScript. It cannot call browser `fetch`. +### Can Homarr be used commercially? -Named requests use the Homarr server. The server applies board permissions and the network policy. - -Before installation, examine the origins, methods, permissions, and actions. Use the same review before publication. - -### Is it secure to expose Homarr to the web? - -Yes, since v0.14.0, we are confident that Homarr is secure enough to be exposed to the web. -Make sure to enable the "allow anonymous access" [option in the settings](/docs/management/boards#access-control), if you want to allow people without an account to be able to see your dashboard (not edit) - -### How do I open the console / log? - -There are two different sources of information: - -- console: This is your client (browser). It can tell us, if there is an issue on the client (crash, bug, ...). -- log: This is your server. It will tell us, if there are issues with connections for the integrations, crashes and errors. - -Both variants _can_ contain personal data. It's recommended, that you don't post them publicly or remove personal data from it. - - - - -> Note: This will not work on most mobile browsers. - -Open your browser and ensure, that Homarr is your current tab. -Press `CTRL` + `SHIFT` + `I` on your keyboard. If this shortcut doesn't work, please use one of the alternatives: https://developer.chrome.com/docs/devtools/open/. -Click on `Console` in the new window, that opened. There, you should see white, orange and sometimes red messages. You can use the Windows Snip & Sketch tool (or your respective tool on Linux / MacOS) to screenshot those messages. - -> Please never execute any commands in the console. Scammers are using the console to let you execute harmful commands. If you want to resolve an issue in Homarr, **you'll never have to execute any commands here** - - - - -This depends on your installation method. If you use Unraid, you can simply click on the App and on `Log`. If you have a bare Docker install, use `docker container logs homarr`. If you used a different name than `homarr` for your container, you need to replace said argument. Here is some additional information about the command: https://geekflare.com/check-docker-logs/. - - - - -### How do I post logs? - -Please check [the section above](#how-do-i-open-the-console--log), on how to obtain logs. Logs should always be posted to https://pastebin.com/ or https://rentry.co/. - -### Can I use Homarr at my company? - -Yes, you can! But please consider a donation, if our work has been useful to you. - -### I think I found a bug. What can I do? - -If you think, that you found a bug, please create an issue here. - -### Why can't I use my custom icons? - -You need to restart the Homarr Docker container after adding icons. - -### Why can't homarr see/ping containers running locally behind GluetunVPN? - -This is because GluetunVPN, and many other docker VPN services, secure their VPN connections with strict firewalls. These firewalls often block access to local containers, even on the same docker network. The workaround for GluetunVPN is to add "- FIREWALL_OUTBOUND_SUBNETS=192.168.1.0/24" into the environmental variables of the docker compose file. If you are using a firewall on your system, you will need to add a rule that allows requests from ip's in the range of 192.168.xxx.xxx . If you are using UFW the command would be "sudo ufw allow from 192.168.0.0/16". -Tip: If you are running your torrent client behind a VPN, and running Sonarr (or something similar) normally, make sure to open your torrent client's port in your firewall. If you don't, Sonarr will not be able to see it. Furthermore, use your machines IP (192.168.x.x) rather then 127.0.0.1 or localhost. - -### Can I get in touch with you? - -Yes, go here to get with us in touch. - -
- -:::tip - -Haven't found the solution to your problem / question? We are eager to help you on [our Discord](/docs/community/get-in-touch#discord) or in a [GitHub Issue](https://github.com/homarr-labs/homarr/issues/new/choose). - -::: +Yes. Homarr is licensed under the [Apache License 2.0](/docs/community/license). Commercial users can support development +through [OpenCollective](/docs/community/donate). diff --git a/apps/docs/docs/community/get-in-touch.mdx b/apps/docs/docs/community/get-in-touch.mdx index eecd2e1f3..17c7a5fa9 100644 --- a/apps/docs/docs/community/get-in-touch.mdx +++ b/apps/docs/docs/community/get-in-touch.mdx @@ -1,24 +1,23 @@ --- -title: Get In Touch -description: Still have a question? Click here! +title: Get in touch +description: Community, support, and private contact channels. tags: - Help - Community --- -We're happy to talk with you! Shoot us a message at the following places: +# Get in touch -## E-Mail +## GitHub -We are open to discuss sponsorships, security vulnerabilities and other private requests through our email. -Please do not report any bugs / feature requests here - they will be ignored and deleted. - -[homarr-labs@proton.me](mailto:homarr-labs@proton.me) +Use the [issue templates](https://github.com/homarr-labs/homarr/issues/new/choose) for bugs and feature requests. ## Discord -We have a Discord Server, where we announce new releases, discuss features and bugs and show off our dashboards. -There are over 4'000 members and we're happy to answer your questions or concerns. -You're also open to discuss new / upcoming features and any offtopic selfhosting content. +Use the [Homarr Discord server](https://discord.gg/aCsmEV5RgA) for community support, release discussion, and dashboard +showcases. -[_![](https://discordapp.com/api/guilds/972958686051962910/widget.png?style=banner2)_](https://discord.gg/aCsmEV5RgA) +## Email + +Use [homarr-labs@proton.me](mailto:homarr-labs@proton.me) for security reports, sponsorships, and other private matters. +Bug reports and feature requests belong on GitHub. diff --git a/apps/docs/docs/community/translations.mdx b/apps/docs/docs/community/translations.mdx index 68eea8a1e..909f94bfd 100644 --- a/apps/docs/docs/community/translations.mdx +++ b/apps/docs/docs/community/translations.mdx @@ -5,51 +5,24 @@ tags: - Translations --- -We want to make Homarr accessible for everyone. -But to do that, we need your help. -We are running a community program that enables everyone to translate Homarr into their language – no programming required. -We are using [Crowdin](https://crowdin.com/) to manage our translations. -You can find the translations [here](https://translate.homarr.dev/). +# Translations -## How to translate +Homarr translations are managed on [Crowdin](https://translate.homarr.dev/). Select a language, translate strings in +context, and submit them for proofreading. Approved translations ship with a later Homarr release. -### Using crowdin's online platform +## Translate from Homarr -Go to the [Crowdin translations](https://translate.homarr.dev/) and select a language you want to translate. -You can then enter the translation mode and start translating. -After you've submitted your translations, a Proofreader will review your changes. -After a translation has been approved, it will be merged to the language development branch. -We merge this one periodically to the development branch. -After the next update of Homarr, all changes from the development branch will be merged, including the changes in the translations. +Select **Crowdin (live translations)** as the application language, connect a Crowdin account, and choose the target +language. Select text in Homarr or use Crowdin's in-context panel to edit a string. -### Using live translate - -You can also help translate homarr directly from the app! -For this you can simply change your language to "Crowdin (live translations)" - -![](./img/crowdin-language-select.png) - -Then you'll be prompted to connect to your Crowdin account and choose the language in which you want to transalte. -You can then start translating directly from the app by selecting some text on the app. -If some text cannot be selected to be edited with the live translation tool, you can still translate it inside of the In-Context popup at the Home tab, it will be red if it's not translated yet. - -![](./img/crowdin-live-translate.png) - -:::caution -Although you are translating directly from the app, your translations will not be directly be available inside of your language, they will be in the next update of Homarr, because we have to push the new translations to a new docker image. - -If you really want to use them you can enable the "preview transaltions" option in the live translate settings, but be aware that this is not recommended for performance reasons. -::: - -:::tip - -Do you want to become a proofreader? [Let us know on our Discord](/docs/community/get-in-touch#discord)! We will add you to the proofreader team. You can then review the translations and approve them. **Note:** You must speak the language fluently, have it as your native language or lots of experience with it. - -::: +Live translation submits changes to Crowdin; it does not update the installed Homarr image. Crowdin's preview option can +show pending translations before the next Homarr release. ## Guidelines -1. Translate with context: Some translations can't be translated 1:1 - they need context. Ensure that your translations make sense in the context. -2. Keep things simple and original - no additional characters are needed. -3. Don't translate the same thing twice - if you see a translation that is already translated, don't translate it again unless you have a better translation. -4. Keep your translations as close to the original as possible. +- Preserve the meaning and context of the English source. +- Keep terminology consistent with existing translations. +- Do not add punctuation, formatting, or explanatory text that is absent from the source. +- Improve an existing translation only when the replacement is more accurate. + +Contact the [Discord community](/docs/community/get-in-touch#discord) to help proofread a language. diff --git a/apps/docs/docs/getting-started/after-the-installation.mdx b/apps/docs/docs/getting-started/after-the-installation.mdx index 695441dfd..7e5712c83 100644 --- a/apps/docs/docs/getting-started/after-the-installation.mdx +++ b/apps/docs/docs/getting-started/after-the-installation.mdx @@ -6,397 +6,76 @@ tags: - Configuration --- -import manageBoardNoApp from "./img/manage-board-no-app.png"; -import currentKeyboardTileEditing from "../management/boards/img/keyboard-tile-editing.png"; -import boardDesktopCurrent from "./img/onboarding-board-desktop-current.png"; -import boardEditModeCurrent from "./img/onboarding-board-edit-mode-current.png"; -import addContentMenuCurrent from "./img/onboarding-add-content-menu-current.png"; -import chooseItemCurrent from "./img/onboarding-choose-item-current.png"; -import editItemCurrent from "./img/onboarding-edit-item-current.png"; -import boardsHomeMobileMenu from "./img/onboarding-boards-home-mobile-menu.png"; -import moveResizeMenuCurrent from "./img/onboarding-move-resize-menu-current.png"; -import currentBoardMobileView from "./img/onboarding-board-mobile-current.png"; +On first launch, onboarding creates the administrator, connects optional services, and builds the first board. A +compatible SQLite backup can also be restored from the welcome screen. -:::tip +If onboarding returns after a restart, check that `/appdata` is writable and persisted. See the +[Docker installation guide](/docs/getting-started/installation/docker). -Read our [glossary](/docs/getting-started/glossary) if you are new to Homarr. +## Core concepts -::: +### Boards -Congratulations on installing Homarr. Now it's time to get yourself familiar with the concepts of Homarr and how to use it. +A **board** is a dashboard page containing apps, widgets, and Containers. Boards can be public or restricted to users +and groups. Each user can choose a home board. -## Onboarding +![Board management with board previews](./img/after-installation-boards.png) -Onboarding appears the first time Homarr starts. Its goal is to create a useful responsive board, not merely an -administrator account. The setup uses one guided studio, so you can keep the safe defaults and finish quickly or review -every detected service before anything is added to the board. +See [Boards](/docs/management/boards) for responsive layouts, access control, appearance, and home-board settings. -:::note +### Apps -If you see this screen repeatedly after restarting the Homarr container, your Docker mounting paths may be missing, -incorrect or read-only. Read [our installation instructions](/docs/getting-started/installation/docker) again to fix this issue. +An **app** is a saved shortcut: a name, URL, icon, and optional status check. Add an App tile or a Bookmarks widget to +show apps on a board. -::: +![App management with saved shortcuts](./img/after-installation-apps.png) -### Restore or start fresh +See [Apps](/docs/management/apps) or [Icons](/docs/advanced/icons). -SQLite installations can restore a complete Homarr database backup from the welcome screen. This restores current -boards, people, apps, integrations, and settings. The pre-1.0 ZIP importer is no longer included. +### Integrations -For a new installation, Homarr first creates either a credentials administrator or an administrator group matching your -LDAP/OIDC provider. The browser that starts setup claims the first-run session; refreshes are safe, while another browser -cannot change credentials or integrations during that setup. +An **integration** is a server-side connection from Homarr to a supported service such as Sonarr, Home Assistant, or +Docker. Integrations provide data and actions to widgets. They can also be linked to apps. -### Setup studio +![Integration catalog with compatible widgets](./img/after-installation-integrations.png) -The studio keeps related choices together: +See [Managing integrations](/docs/management/integrations) and the +[integration catalog](/docs/category/integrations). -1. **Essentials** sets the default language, color scheme, analytics preference, and the usual host, IP address, domain, or reverse-proxy path used by your services. URL suggestions can use separate ports, subdomains, or one path per service. -2. **Discover** checks the actual database, Docker-compatible sockets, Kubernetes configuration, Workshop, and Assistant capabilities. Unavailable sources never block manual setup. -3. **Connect** shows detected integrations and apps first, identifying whether each app came from an explicit [`homarr.*` or Homepage Docker label](/docs/integrations/docker-labels) or image matching. Select several integrations and apps at once, review every URL, and use the service-specific link to open its API-key settings when one is available. If a container has no published port or URL label, add its HTTP or HTTPS address before importing it. -4. **Board** previews the Base layout, colors, widget radius, sidebars, selected apps, and widgets inferred from integrations or Docker labels. Choose 8 columns for a focused board, 10 for a balanced board, 12 for a wide board, or use the slider for a custom width up to 24 columns. Homarr still creates and reflows the protected Mobile layout automatically. A fast setup adds the integration-free Clock, Weather, and Bookmarks starter widgets. -5. **Extend** explains and optionally configures Assistant, the community Workshop, and the separate Homarr MCP endpoint. -6. **Review** tests the selected connections, then saves integrations, apps, widgets, settings, and the exact first board together. If any part fails, the database changes are rolled back and your form stays available to correct. +### Widgets -Docker discovery reports each configured host separately. Results from reachable hosts remain selectable if another socket -is unavailable, which is useful for remote Docker, rootless Docker, Synology, and mixed deployments. On Kubernetes or -bare-metal installations without a Docker socket, enter services manually and use the same integration catalog. +A **widget** is a board tile. Some widgets work on their own; others require one or more integrations. Configuration, +supported integrations, and non-obvious limitations are documented on each widget page. -After setup, **Open my board** takes you directly to the configured board. The in-product tour then introduces edit mode, -responsive layouts, widgets, and search without delaying completion. +![Board in edit mode with the add-content menu](./img/after-installation-widgets.png) -## Creating another board +See the [widget catalog](/docs/category/widgets). -In Homarr, you organize your apps and widgets on boards. -Boards use fixed-size tiles so the same widget keeps the same proportions on every screen. -Drag, resize, and section controls are available in edit mode. -Onboarding already created the first board. To create another one, navigate to `Manage` > `Boards` > `New board`: -![](./img/manage-create-board-button.png) +### Containers and rails -A board must always have a name and can either be public or private. -Public boards are also accessible for users, that are not logged in ([see access control for boards](/docs/management/boards/#access-control)). +A **Container** groups board items and can be nested. A **rail** reserves a fixed area at the left or right of a +responsive layout. Both are configured in board edit mode. -![](./img/manage-create-board-modal.png) +![Board layout settings with fixed sidebars](./img/after-installation-containers-rails.png) -Congratulations - you've just created another board. You can see the boards you have access to on this page: +See [Boards](/docs/management/boards#containers-and-rails). -
- Boards management page showing a Home badge and separate desktop and mobile home-board menu entries -
The Boards page selects the board opened from Home separately for desktop and mobile.
-
+### Users, groups, and permissions -The board marked **Home** is the board opened from the desktop Home route. **Set as your mobile board** selects which board -opens on phones. This is separate from the **Mobile** layout: the home-board setting chooses a board, while **Mobile** and -**Base** are responsive layouts inside that board. A phone can therefore open a different home board and still use that -board's Mobile layout. +Users inherit permissions and default boards from their groups. Resource-specific access can further restrict boards +and integrations. -New boards start with **Mobile** and **Base** responsive layouts automatically, so you can edit the board for phones and -desktops without creating extra layouts first. Mobile starts at `0px` with 3 columns and Base at `768px` with 10 columns. -Each layout keeps its own tile positions and sizes. +![Group permission settings](./img/after-installation-users-permissions.png) -## Add your first app to Homarr +See [Users and groups](/docs/management/users) and [single sign-on](/docs/advanced/single-sign-on). -To add links to your dashboard, you must first add them as an "app". -Navigate to this page to add an app: +## Explore further -![](./img/manage-navigate-apps.png) +- [Server settings](/docs/management/settings) +- [Assistant](/docs/management/assistant) +- [Custom Widgets](/docs/management/custom-widgets) +- [Community Workshop](/docs/workshop) +- [API](/docs/management/api) and [MCP](/docs/management/mcp) +- [Keyboard shortcuts](/docs/advanced/keyboard-shortcuts) -Next, click on the `New app` button. You'll need to provide a name and an icon to create an app. -The name must be at least one character long but you can provide any image URL for the icon. -Homarr ships with over 11K icons - so you can just search by entering a search text instead. - -![](./img/manage-add-app-form.png) - -After you created the app, you'll see in on the apps page: - -![](./img/manage-created-app.png) - -## Arrange and organize your board - -Let's add your freshly created app, from the previous step, to the board. -To do this, edit your previously created board by clicking on the big `Open board` button: - -
- Current Homarr board opened from the Boards page -
Open a board to view its dashboard, then enter edit mode to arrange its content.
-
- -Here you have the following options in the header: - -![](./img/manage-board-header.png) - -- **Search**: Here you can search for data. You can search for integrations, boards, actions, sites and much more. Some actions may be context dependent (eg. will only show when certain widgets are on your page) -- **Edit board**: Clicking this button will toggle edit mode. In this mode you can edit the contents of your board. -- **Settings**: Clicking this button will redirect you to a settings page where you can adjust the board settings (page title, colors, ...). -- **Profile**: This avatar will be visible on every page. Its menu includes the board switcher; press `Shift+C` to open - it directly. The current board is left out of the results. - -When entering the edit mode, you'll get some additional buttons to work with: - -
- Current Homarr board editor with tile controls visible -
The current editor keeps the board visible while its editing controls are available.
-
- -- **Add board content**: Click this button to create a new item, app, integration, or Container. -- **Save board**: Click this button to save your changes and leave edit mode. If you leave with unsaved changes, Homarr asks whether to discard them. - -Outside edit mode, right-click a widget for its live status, refresh, settings, quick options, and supported actions. -Hold `Shift` while hovering a widget that supports advanced view to expand it in place while the rest of the board -stays visible but dimmed. Release `Shift` to close it. Hold `Shift` plus `Ctrl` on Windows/Linux or `Cmd` on macOS to -keep its advanced view open until you close it. Widgets without a distinct advanced experience adapt in place. - -To continue, click **New item** in the add-content menu. New content is placed at the first available position on the main -canvas; it is not inserted at a clicked empty cell or directly into a rail or Container: - -
- Current add board content menu with item, app, integration, and Container actions -
The add-content menu provides the four supported ways to place new content on the board.
-
- -Next, you can choose what item you'd like to add. -We will discuss the other options in the following sections - for now choose "App" to continue. - -
- Current item picker showing the App card and other item types -
Choose the App item from the current picker to add an app tile.
-
- -As soon as you chose the app, the modal will close and you'll get the following item on your board: - -Screenshot of the No app element on the board - -This is expected, because you haven't told Homarr what app it should show in this item. -To configure this, click on the small 3 dots at the top of the item in the edit mode and choose "Edit item" in the menu. - -
- Current board tile menu showing Edit item and Move or resize item -
The tile menu contains the item editor and the separate move-and-resize tools.
-
- -In the modal you can edit the app that you want to display: - -
- Current Edit item modal for an App tile -
- The Edit item workspace previews option changes as you configure the tile. Save changes to apply them to the board. -
-
- -When adding a widget, set its initial grid width and height directly in the preview. These size controls are only shown before the widget is added. - -As soon as you save your changes, the tile on the board will refresh and display your app. -Resize from any visible edge or corner handle. For a Container, activate its top-left grip before using its resize handles. -Press and hold a handle, move the pointer, and release it when the tile has the size you want. - -To move a tile in edit mode, press and hold its inert content area, move it to the desired position, and release it. -Widget content is disabled while editing so its controls do not intercept the drag; use the tile's settings button for edit actions. -The tile snaps to the grid. A single compatible collision may swap the two items when both resulting placements fit; -otherwise the collision chain reflows neighboring tiles automatically. - -Every `1 × 1` tile has a logical content size of `200 × 200` pixels. -Larger tiles use multiples of that fixed unit, with a consistent gap between cells. -Homarr scales the complete board uniformly, like zooming a page. -The complete canvas always fits the available width without horizontal board scrolling. Below 100%, Homarr preserves the -widget's readable typography and control density instead of shrinking each widget independently. -It does not squeeze or reflow the content of individual widgets, so a widget keeps the same design and proportions across screen sizes. - -On a narrow screen, Homarr uses the **Mobile layout** for the selected board and stacks the board content vertically while -preserving each widget's fixed logical proportions: - -
- Homarr's Mobile layout in a 390-pixel-wide viewport, with tiles scaled to fit and stacked vertically -
- At phone width, the selected board uses its Mobile layout and fits the complete canvas to the viewport. -
-
- -:::note - -Viewing a board initially uses the lightweight, non-interactive layout. -For users with edit access, Homarr prepares drag-and-drop and resize controls in the background after the board becomes interactive. -If you enter edit mode before that finishes, the existing board stays visible until the editor is ready. - -::: - -:::tip - -We recommend you to experiment for a few minutes, before you start building your actual dashboard. -This helps you to explore the capabilities of Homarr before you build your board in a suboptimal way. - -::: - -Keyboard users can focus a tile, press Enter or Space, then use arrow keys to move and Shift plus arrow keys to resize -within its current canvas, rail, or Container. Press Escape to stop keyboard editing. Touch dragging starts after a short -hold of about `200 ms`; resize handles accept direct touch input. During a pointer or touch move or resize, press Escape -to cancel and restore the previous layout. For cross-grid moves or precise numeric controls, choose **Move / resize item** -from the tile's edit menu. -Keyboard commands at a grid boundary or minimum tile size are ignored and announced; they do not move or shrink the tile. - -A board tile focused for keyboard editing - -Open **Move / resize item** from the tile menu to move the tile to another section or rail and enter precise numeric -coordinates and dimensions. After making changes, click **Save board** to persist them and leave edit mode. - -## Adding your first integration - -Now it's time to integrate some basic data into your board. -To do this, we first need to create an integration. -An integration is a connection between Homarr and a third party application - usually something that you run and deploy yourself. - -Navigate to `Manage` > `Integrations` (for example via your user menu). -As an example, we are going to use the public demo instance of **Dash.** - a popular application to monitor CPU / hardware usage. -Choose the **Dash.** integration from the list of available integrations: - -![](./img/choose-integration.gif) - -Next, choose a name (or leave it at default), enter `https://dash.mauz.dev/` as the URL in the form and click on `Test connection and create`. -Pressing the save button will perform a test request to the integration, to confirm that the networking setup is working as expected. -Sometimes invalid configurations, firewalls and other mistakes can lead to connectivity problems - [follow this guide here](/docs/management/integrations/#troubleshooting-connection) if you experience issues. - -If connection was successful, you will be redirect back to the list of integrations. -Now let's embed it to your board (see next section). - -:::note - -Some integrations may require additional configuration, such as a username, password or API tokens. -Depending on your networking setup and applications, the connection from Homarr might also get blocked by firewalls, -the target application or your router. - -::: - -## Embed integration data using widgets - -Let's add your integration, that you have configured in the section above, as a widget to your board. -First, navigate back to your board that you want to add it to. -Next, enter edit mode again and add another item to your board: - -
- Current add board content menu with item, app, integration, and Container actions -
Use the same add-content menu to place an integration widget on the board.
-
- -Instead of choosing an app, let's choose `System Health Monitoring` this time. -Click on "Add to board": - -![](./img/manage-board-header-choose-system-health.png) - -Resize the item slightly and then edit it using the three dots menu at the top: - -![](./img/edit-system-health-widget.gif) - -Next, choose your newly created Dash. integration in the integrations dropdown: - -![](./img/manage-board-edit-system-health.png) - -:::note - -Some widgets may support multiple integrations at the same time. -If they do not support multiple integrations, you will be unable to select more than one. - -::: - -Confirm your changes by pressing save. -Editing a widget will trigger a data update and data will soon appear: - -![](./img/widget-system-health.png) - -As with every change, click **Save board** to persist your board changes and leave edit mode. - -## Organizing items with Containers - -Containers are resizable areas for apps, widgets, and nested Containers. -The same Container works on the main canvas, inside a fixed rail, or inside another Container. -Each Container can configure: - -- Its label and whether that label is visible. -- Allow or disable collapsing. -- Show or hide **Open all in new tabs**. -- Change its border color and custom CSS classes. - -Open the add-content menu and choose **New container**. -In edit mode, move and resize it like any other item, then drag items into or out of it. -Nested content stays within the Container's bounds. -While resizing, the solid outline follows the pointer continuously and the dashed grid preview shows the size that will be saved on release. - -### Collapsing and opening apps - -Users can collapse an eligible Container like an accordion in view mode without changing its saved expanded size. -The full-width header becomes the compact expansion bar, so the half-row state has no empty pill-shaped spacer. -Expanding it restores its bounds and makes room for its contents. -If **Open all in new tabs** is enabled, the Container menu can open every app link it contains. - -### Fixed rails - -Open the board's **Layout** settings to enable the left or right rail for each responsive layout. -Choose one, two, or three columns with the slider and use the preview to check the remaining canvas width. -The rail reserves those columns from the dashboard, so Homarr moves canvas items into the next available positions. -Rail content stays visible while the page scrolls and remains editable. -Each responsive layout keeps its own rail widths, item positions, and item sizes. - -## Guided tours - -After completing the onboarding, Homarr provides interactive guided tours to help you discover key features. - -### Management tour - -When you first visit the management area (`/manage`), Homarr walks you through the main pages: boards, apps, integrations, and users (admin only). -Each page highlights the list view and the create action so you know where to find and add things. - -### Board tour - -When you first open a board, a tour highlights the board header elements: search, edit mode, settings, and the user menu. - -### Tour controls - -- Press **Enter** (or click **Next**) to advance through tour steps -- Tours auto-start on first visit and do not repeat once completed -- Tours are skipped on mobile screens (below `sm` breakpoint) -- You can **reset tours** from the user settings page under **Manage > Users > [Your user] > General** - -## Next steps - -You're done with the basic setup 🔥. Now it's time to organize and customize even more. -We highly recommend you to experiment with different options, styles and configurations. -See these curated pages for your next steps: - -- Create new apps using the [apps management](/docs/management/apps/) -- Customize your board or add more boards using the [boards management](/docs/management/boards/) -- Integrate software that you use using the [integrations management](/docs/management/integrations/) -- Choose from our beautiful and interactive [widgets](/docs/category/widgets) -- See [all supported integrations](/docs/category/integrations) -- Integrate with Homarr with your own application using [the API](/docs/management/api/) - -:::danger - -The Homarr Team will never ask for your credentials. Do not send people your credentials, as they manage the access to your applications and can cause harm to your device if they are abused. - -::: +See the [glossary](/docs/getting-started/glossary) for a compact list of Homarr terms. diff --git a/apps/docs/docs/getting-started/glossary.mdx b/apps/docs/docs/getting-started/glossary.mdx index 989c71e1c..20498be53 100644 --- a/apps/docs/docs/getting-started/glossary.mdx +++ b/apps/docs/docs/getting-started/glossary.mdx @@ -2,12 +2,19 @@ This glossary explains Homarr's main components and the terms used for them. -| Term | Definition | -| ----------- | --------------------------------------------------------------------------------------- | -| Apps | A piece of software that you or a third party hosts (for example, Google) | -| Integration | A connection to a service outside of Homarr | -| Container | A resizable area that can hold apps, widgets, and nested Containers | -| Widget | A tile that uses your integrations to display data or enables you to interact with them | -| Edit mode | A temporary state where you can drag, resize, edit, or customize your board | -| Board | A customizable page where apps, widgets, and Containers are arranged | -| Tasks | Workloads that are performed in the background, even if no user is present | +| Term | Definition | +| --------------- | -------------------------------------------------------------------------------- | +| App | A saved shortcut with a name, destination, icon, and optional status check | +| Assistant | A conversation interface that can use model responses and Homarr tools | +| Board | A dashboard page where apps, widgets, and Containers are arranged | +| Container | A resizable board area containing apps, widgets, or nested Containers | +| Custom Widget | A validated definition for an API-backed board tile | +| Edit mode | The board state used to add, move, resize, configure, or remove content | +| Homarr provider | An Assistant provider routed through Workshop with a per-user allowance | +| Integration | A server-side connection from Homarr to a supported service | +| Layout | An arrangement of board items selected for a viewport width | +| Provider | The model API selected for Assistant | +| Rail | A fixed area at the left or right of a non-Mobile board layout | +| Task | A background workload that runs without an active browser session | +| Widget | A board tile that displays information or provides actions | +| Workshop | A separate community service for sharing Custom Widget definitions and board CSS | diff --git a/apps/docs/docs/getting-started/img/after-installation-apps.png b/apps/docs/docs/getting-started/img/after-installation-apps.png new file mode 100644 index 000000000..96270fe56 Binary files /dev/null and b/apps/docs/docs/getting-started/img/after-installation-apps.png differ diff --git a/apps/docs/docs/getting-started/img/after-installation-boards.png b/apps/docs/docs/getting-started/img/after-installation-boards.png new file mode 100644 index 000000000..0a83d3eda Binary files /dev/null and b/apps/docs/docs/getting-started/img/after-installation-boards.png differ diff --git a/apps/docs/docs/getting-started/img/after-installation-containers-rails.png b/apps/docs/docs/getting-started/img/after-installation-containers-rails.png new file mode 100644 index 000000000..645c76b83 Binary files /dev/null and b/apps/docs/docs/getting-started/img/after-installation-containers-rails.png differ diff --git a/apps/docs/docs/getting-started/img/after-installation-integrations.png b/apps/docs/docs/getting-started/img/after-installation-integrations.png new file mode 100644 index 000000000..3754ee2c2 Binary files /dev/null and b/apps/docs/docs/getting-started/img/after-installation-integrations.png differ diff --git a/apps/docs/docs/getting-started/img/after-installation-users-permissions.png b/apps/docs/docs/getting-started/img/after-installation-users-permissions.png new file mode 100644 index 000000000..078a6ad42 Binary files /dev/null and b/apps/docs/docs/getting-started/img/after-installation-users-permissions.png differ diff --git a/apps/docs/docs/getting-started/img/after-installation-widgets.png b/apps/docs/docs/getting-started/img/after-installation-widgets.png new file mode 100644 index 000000000..9edc4f7b1 Binary files /dev/null and b/apps/docs/docs/getting-started/img/after-installation-widgets.png differ diff --git a/apps/docs/docs/getting-started/img/board-mobile-view.png b/apps/docs/docs/getting-started/img/board-mobile-view.png deleted file mode 100644 index 87686b455..000000000 Binary files a/apps/docs/docs/getting-started/img/board-mobile-view.png and /dev/null differ diff --git a/apps/docs/docs/getting-started/img/onboarding-add-content-menu-current.png b/apps/docs/docs/getting-started/img/onboarding-add-content-menu-current.png deleted file mode 100644 index 3d05ac9c4..000000000 Binary files a/apps/docs/docs/getting-started/img/onboarding-add-content-menu-current.png and /dev/null differ diff --git a/apps/docs/docs/getting-started/img/onboarding-board-desktop-current.png b/apps/docs/docs/getting-started/img/onboarding-board-desktop-current.png deleted file mode 100644 index ece8f4b40..000000000 Binary files a/apps/docs/docs/getting-started/img/onboarding-board-desktop-current.png and /dev/null differ diff --git a/apps/docs/docs/getting-started/img/onboarding-board-edit-mode-current.png b/apps/docs/docs/getting-started/img/onboarding-board-edit-mode-current.png deleted file mode 100644 index e0bbac8b7..000000000 Binary files a/apps/docs/docs/getting-started/img/onboarding-board-edit-mode-current.png and /dev/null differ diff --git a/apps/docs/docs/getting-started/img/onboarding-board-mobile-current.png b/apps/docs/docs/getting-started/img/onboarding-board-mobile-current.png deleted file mode 100644 index d84733829..000000000 Binary files a/apps/docs/docs/getting-started/img/onboarding-board-mobile-current.png and /dev/null differ diff --git a/apps/docs/docs/getting-started/img/onboarding-boards-home-mobile-menu.png b/apps/docs/docs/getting-started/img/onboarding-boards-home-mobile-menu.png deleted file mode 100644 index f7332bba4..000000000 Binary files a/apps/docs/docs/getting-started/img/onboarding-boards-home-mobile-menu.png and /dev/null differ diff --git a/apps/docs/docs/getting-started/img/onboarding-choose-item-current.png b/apps/docs/docs/getting-started/img/onboarding-choose-item-current.png deleted file mode 100644 index 3fcb2f4bb..000000000 Binary files a/apps/docs/docs/getting-started/img/onboarding-choose-item-current.png and /dev/null differ diff --git a/apps/docs/docs/getting-started/img/onboarding-edit-item-current.png b/apps/docs/docs/getting-started/img/onboarding-edit-item-current.png deleted file mode 100644 index b86859e7e..000000000 Binary files a/apps/docs/docs/getting-started/img/onboarding-edit-item-current.png and /dev/null differ diff --git a/apps/docs/docs/getting-started/img/onboarding-move-resize-menu-current.png b/apps/docs/docs/getting-started/img/onboarding-move-resize-menu-current.png deleted file mode 100644 index c6559a58d..000000000 Binary files a/apps/docs/docs/getting-started/img/onboarding-move-resize-menu-current.png and /dev/null differ diff --git a/apps/docs/docs/getting-started/index.mdx b/apps/docs/docs/getting-started/index.mdx index 0d6a44a4e..e90481a44 100644 --- a/apps/docs/docs/getting-started/index.mdx +++ b/apps/docs/docs/getting-started/index.mdx @@ -1,45 +1,31 @@ --- -title: Prerequisites +title: Getting started sidebar_position: 1 tags: - Getting Started - Installation - - Docker - - Unraid --- -import Link from "@docusaurus/Link"; -import { IconArrowRight } from "@tabler/icons-react"; +import { + GettingStartedOverview, + InstallationPaths, +} from "@site/src/components/pages/getting-started/getting-started-overview"; -Before you try to install Homarr, please review if your device meets the requirements. -Installing on an unsupported device may lead to unstable behaviour and no support will be provided. + -## Hardware +## Requirements -- At least 500MB RAM -- At least 600MB of free disk space for the Docker image. SSD is preferred. -- Single or dual core CPU -- Stable network connection, Wi-Fi use is not recommended +- `linux/amd64` or `linux/arm64`; +- 500 MB RAM; +- 600 MB free disk space for the container image; +- a persistent writable `/appdata` directory. -## Architecture +`linux/arm/v7` is not supported. -We build Homarr for a bunch of different architectures, including ARM. Please ensure that your device architecture is supported by Homarr. We won't be able to provide support for unusual or outdated architectures. +## Choose an installation method -| Architecture | Supported | -| ------------ | ---------------- | -| linux/amd64 | ✅ Supported | -| linux/arm64 | ✅ Supported | -| linux/arm/v7 | ❌ Not supported | + -## Getting started with installation - - -
- Go to Installation - -
- +After Homarr starts, open it in a browser and complete onboarding. Then continue with +[After the installation](/docs/getting-started/after-the-installation) for the core concepts and the most useful next +links. diff --git a/apps/docs/docs/getting-started/installation/docker.mdx b/apps/docs/docs/getting-started/installation/docker.mdx index 5a56a848a..e721c5933 100644 --- a/apps/docs/docs/getting-started/installation/docker.mdx +++ b/apps/docs/docs/getting-started/installation/docker.mdx @@ -2,106 +2,52 @@ import { DockerInstallSnippet } from "@site/src/components/pages/installation/do # Docker -Docker is our recommended installation method for beginners and professionals. -It is easy to use, ships with all dependencies inside a single container and is easy to use and maintain. -It requires at least some basic knowledge of [Docker](https://www.docker.com/). -We recommend [NetworkChuck's Docker Containers 101](https://www.youtube.com/watch?v=eGz9DS-aIeY) as a good start for complete beginners. +Docker Compose is the recommended installation method. Install +[Docker Engine](https://docs.docker.com/engine/install/) and the +[Compose plugin](https://docs.docker.com/compose/install/). -## Docker compose - -### Prerequisites - -- A Linux or Windows based system that meets the [hardware prerequisites](/docs/getting-started/#hardware) and [architecture prerequisites](/docs/getting-started/#architecture). -- [Docker](https://docs.docker.com/get-docker/) -- [Docker Compose](https://docs.docker.com/compose/install/) - _preinstalled on many systems nowadays_ - -### Installation +## Docker Compose -Finally, run ``docker compose up -d`` in the same directory. This will start the Homarr container in the background. -:::caution +Start Homarr from the directory containing `docker-compose.yaml`: -Docker compose creates a network by default. Some integrations may not work (specifically Dash.) when the network internal hostname is used since clients do not know this name. It is recommended that you either use a local network wide hostname or the IP directly. An alternative is to create a DNS record with the same internal compose stack hostname for all clients outside. +```sh +docker compose up -d +``` -::: +Persist `/appdata`; it contains the database and configuration. Mount the Docker socket only when Homarr needs Docker +discovery or management. -### Updating +Integration URLs must be reachable from the Homarr container. Browser-facing app URLs may use a different hostname; +see [Managing integrations](/docs/management/integrations#configuration). -To update, navigate to the directory with the `docker-compose.yaml` located. +### Update -- Stop Homarr using `docker compose down` -- Pull the newest image of Homarr using `docker compose pull` -- Start Homarr again using `docker compose up -d` (`-d` for detached mode - start in background) -- Delete the old image using `docker image prune` (_Warning: this also removes you other unused images - not just Homarr_) +```sh +docker compose pull +docker compose up -d +``` -You can automate this process using [Watchtower](https://containrrr.dev/watchtower/). +### Uninstall -### Uninstalling +`docker compose down` removes the containers and Compose network. Delete the configured `/appdata` host directory or +volume only when the Homarr data is no longer needed. -To uninstall, navigate to the directory with the `docker-compose.yaml` located. +## Docker CLI -- Stop Homarr using `docker compose down` -- Delete the created directories & files on your root file system (check `docker-compose.yaml` file for your specific locations) -- Delete compose file using `rm docker-compose.yaml` -- Prune unused Docker images using `docker image prune` (_Warning: this also removes you other unused images - not just Homarr_) -- (Optional): Prune any network or volumes if you use any. -- (Optional): Remove Homarr from your reverse proxy, VPNs or tunnels if you use any. +The equivalent standalone container is: -## Docker standalone - -:::caution - -[Docker Compose](#docker-compose) is easier and recommended for beginners. Consider using compose instead. - -::: - -### Prerequisites - -- A Linux or Windows based system that meets the [hardware prerequisites](/docs/getting-started/#hardware) and [architecture prerequisites](/docs/getting-started/#architecture). -- [Docker](https://docs.docker.com/get-docker/) - -### Installation - -To install Homarr using Docker, simply run the following command. - -```bash -docker run \ +```sh +docker run \ --name homarr \ --restart unless-stopped \ -p 7575:7575 \ -v /var/run/docker.sock:/var/run/docker.sock \ - -v /homarr/appdata:/appdata \ + -v /absolute/path/to/homarr/appdata:/appdata \ -e SECRET_ENCRYPTION_KEY='your_64_character_hex_string' \ -d ghcr.io/homarr-labs/homarr:latest ``` -:::note - -Docker will mount the configuration files and icons to your host machine. Please make sure to replace `` from the docker run command with your desired storage location. The path must be absolute. - -::: - -### Updating - -To update Homarr, you must remove your container first. Make sure that you've mounted your data and that you have access to it, so your configuration doesn't get lost. - -1. Run `docker rm homarr` to remove the container. -2. Pull the latest Homarr image `docker pull ghcr.io/homarr-labs/homarr:latest`. -3. Re-run the command you used to install Homarr. - -This process can get tideous, if you update frequently. Thus, we recommend [using docker-compose](#docker-compose) - -:::tip - -Want to update all your containers automatically? Checkout [Watchtower](https://containrrr.dev/watchtower/) a service which will automatically update your containers on a set interval. - -::: - -### Uninstalling - -1. Obtain the container ID of your Homarr container using `docker ps | grep homarr`. -2. Delete the container using `docker rm ` -3. Prune unused Docker images using `docker image prune` (_Warning: this also removes you other unused images - not just Homarr_) -4. (Optional): Prune any network or volumes if you use any. -5. (Optional): Remove Homarr from your reverse proxy, VPNs or tunnels if you use any. +Remove the Docker socket mount when it is not required. To update, pull the current image, recreate the container with +the same arguments, and keep the `/appdata` mount and `SECRET_ENCRYPTION_KEY` unchanged. diff --git a/apps/docs/docs/getting-started/installation/portainer.mdx b/apps/docs/docs/getting-started/installation/portainer.mdx index 0442b215e..a502b5c3e 100644 --- a/apps/docs/docs/getting-started/installation/portainer.mdx +++ b/apps/docs/docs/getting-started/installation/portainer.mdx @@ -1,14 +1,8 @@ # Portainer -## Portainer Stacks +## Install with a stack -### Prerequisites - -- [Portainer Stacks](https://www.portainer.io/blog/stacks-docker-compose-the-portainer-way) - -### Installing - -To install Homarr using Portainer Stacks, simply create a new stack and paste the following code into it. +Create a Portainer stack with this Compose file: ```yml title="docker-compose.yml" #---------------------------------------------------------------------# @@ -28,21 +22,12 @@ services: - "7575:7575" ``` -:::note -Portainer will mount the files to your host machine. Please make sure to replace `` from the docker run command with your desired storage location. The path must be absolute. -::: - -Then, click on `Deploy the stack` and wait until the container has started. - -:::tip - -If you're unsure how to create a stack, checkout the [Portainer Documentation](https://docs.portainer.io/user/docker/stacks/add). - -::: +Replace `` with an absolute host path, generate `SECRET_ENCRYPTION_KEY`, then deploy the stack. See +[Portainer's stack documentation](https://docs.portainer.io/user/docker/stacks/add) for Portainer-specific options. ### Updating -To update Homarr using Docker Compose or Portainer Stacks, simply pull the latest image and restart the container. +Pull the current image and redeploy the stack: 1. Run `docker pull ghcr.io/homarr-labs/homarr:latest` to pull the latest image. 2. Re-run `docker-compose up -d` or re-deploy the stack in Portainer. diff --git a/apps/docs/docs/getting-started/installation/qnap.mdx b/apps/docs/docs/getting-started/installation/qnap.mdx index b8c1f977b..2558e7184 100644 --- a/apps/docs/docs/getting-started/installation/qnap.mdx +++ b/apps/docs/docs/getting-started/installation/qnap.mdx @@ -1,9 +1,11 @@ # QNAP :::caution -QNAP installation guide has not updated to 1.0 yet. There guide is still for 0.15.10. + +The available QNAP guides target Homarr 0.15.10 and have not been updated for 1.0. + ::: -When installing on QNAP, we recommend you to install Homarr using [Container Station](https://www.qnap.com/en/software/container-station) or [this third-party image](https://www.myqnap.org/product/homarr/). - -There is also a guide available, but note that it is written in Chinese: https://post.smzdm.com/p/awzm7op2/ +Run Homarr with [Container Station](https://www.qnap.com/en/software/container-station) or the +[third-party QNAP package](https://www.myqnap.org/product/homarr/). A community +[Container Station guide](https://post.smzdm.com/p/awzm7op2/) is available in Chinese. diff --git a/apps/docs/docs/getting-started/installation/runtipi.mdx b/apps/docs/docs/getting-started/installation/runtipi.mdx index c2b2823b7..d78a7a508 100644 --- a/apps/docs/docs/getting-started/installation/runtipi.mdx +++ b/apps/docs/docs/getting-started/installation/runtipi.mdx @@ -1,33 +1,12 @@ # Runtipi -Runtipi is a self-hosted orchestrator that makes it easy to manage and run multiple services on a single server. It is based on Docker and comes with a simple web interface to manage your services. Runtipi is designed to be easy to use, so you don't have to worry about manual configuration or networking. +Homarr is available in the default [Runtipi](https://runtipi.io) app store. -https://runtipi.io +## Installation -## Prerequisites +Install **Homarr** from the Runtipi app store and select either a port or domain for access. -- [Runtipi](https://runtipi.io/docs/getting-started/installation) +Runtipi manages start, stop, update, backup, and log operations under **My apps → Homarr**. Use a +[user-config](https://runtipi.io/docs/guides/customize-app-config) to override the generated Compose configuration. -# Installation - -Installing Homarr is pretty untuitive, the app is available in the default appstore : - -1. Search for **"Homarr"** in the App-Store page and select it -2. Click on **"Install"**. -3. Choose the method you want to access Homarr, through any port or domain name then select **"Install"** - -# Maintenance - -After installation, all you need is available from the WebUI in **"My apps"** > **"Homarr"** : - -- Start/Stop -- Update -- Backup -- Logs - -If you like to tinker with your apps, you can also edit your app's docker-compose with a [user-config](https://runtipi.io/docs/guides/customize-app-config). - -# Getting help - -- If you are looking for help with anything in Runtipi. They provide support on their [Discord](https://discord.gg/Bu9qEPnHsc) and [forums](https://forums.runtipi.io/). If you found vulnerabilities or bugs, [create a new issue here](https://github.com/runtipi/runtipi-appstore/issues). -- If you are looking to report a bug, vulnerability or request a new feature for Homarr, use https://github.com/homarr-labs/homarr . You can ask for help on our Discord. +See the [Runtipi installation documentation](https://runtipi.io/docs/getting-started/installation) for host setup. diff --git a/apps/docs/docs/integrations/docker/index.mdx b/apps/docs/docs/integrations/docker/index.mdx index 55069ae0c..c086b317d 100644 --- a/apps/docs/docs/integrations/docker/index.mdx +++ b/apps/docs/docs/integrations/docker/index.mdx @@ -1,114 +1,25 @@ --- title: "Docker" -description: "Docker is a platform where you can run your applications in containers, allowing for easy deployment and management of applications." +description: "Connect Homarr to Docker-compatible container engines." hide_title: true --- import { IntegrationHeader } from "@site/src/components/integrations/header"; import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; -import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; -import { IconBrandDocker, IconTool } from "@tabler/icons-react"; import { dockerIntegration } from "."; import { dockerContainersWidget } from "@site/docs/widgets/docker-containers"; -### Widgets & Capabilities +### Widgets and capabilities - + -## Connecting Docker to Homarr +Docker endpoints are configured with environment variables rather than under **Management → Integrations**. -Docker connections come directly from Homarr's environment variables. They are automatically available in the Docker management table and Docker widget; you do not create a Docker integration under **Management → Integrations**. +## Local socket -If Homarr runs directly on a host with Docker installed, it uses `/var/run/docker.sock` by default. When Homarr runs in a container, mount the [Docker socket](https://docs.docker.com/engine/security/protect-access/) into it so Homarr can interact with Docker. - -In Docker Compose, you can simply add this line: - -```yaml {10} -#---------------------------------------------------------------------# -# Homarr - A simple, yet powerful dashboard for your server. # -#---------------------------------------------------------------------# -services: - homarr: - container_name: homarr - image: ghcr.io/homarr-labs/homarr:latest - restart: unless-stopped - volumes: - - /var/run/docker.sock:/var/run/docker.sock # <--- add this line here! - - ./homarr/appdata:/appdata - environment: - - SECRET_ENCRYPTION_KEY=your_64_character_hex_string # <--- can be generated with `openssl rand -hex 32` - ports: - - "7575:7575" -``` - -With docker run, add this parameter: `-v /var/run/docker.sock:/var/run/docker.sock`. -In Windows, you'll need to adjust the slashes: `-v //var/run/docker.sock:/var/run/docker.sock` - -### Using Podman - -On Linux, Homarr can connect to Podman's [Docker-compatible API](https://docs.podman.io/en/latest/markdown/podman-system-service.1.html). -The Podman API socket must be running and mounted into the Homarr container. -The socket grants full access to Podman, including arbitrary code execution as the user running the API, so only mount it into trusted containers. - -For rootless Podman, enable the socket for the user that runs Homarr: - -```bash -systemctl --user enable --now podman.socket -``` - -The rootless socket is located at `$XDG_RUNTIME_DIR/podman/podman.sock` (usually `/run/user//podman/podman.sock`). -You can confirm the path with: - -```bash -podman info --format '{{.Host.RemoteSocket.Path}}' -``` - -Mount that socket into the Homarr container and point `DOCKER_SOCKET_PATHS` to its path **inside** the container: - -```yaml -services: - homarr: - container_name: homarr - image: ghcr.io/homarr-labs/homarr:latest - restart: unless-stopped - volumes: - - ${XDG_RUNTIME_DIR}/podman/podman.sock:/var/run/podman.sock - - ./homarr/appdata:/appdata - environment: - SECRET_ENCRYPTION_KEY: your_64_character_hex_string - DOCKER_SOCKET_PATHS: /var/run/podman.sock - ports: - - "7575:7575" -``` - -Start Homarr with `podman compose up -d`. -Run the compose project as the same user that owns the rootless Podman socket so `$XDG_RUNTIME_DIR` resolves to the correct path. -To keep the user socket available after logout and across reboots, enable lingering with `loginctl enable-linger `. - -For rootful Podman, enable the system socket with `sudo systemctl enable --now podman.socket`. -Its default path is `/run/podman/podman.sock`; mount that path instead and start Homarr with `sudo podman compose up -d`. - -:::note SELinux -On systems with SELinux enabled, Podman's documentation recommends disabling label separation for a container that accesses the API socket. -Add the following to the Homarr service: - -```yaml -security_opt: - - label=disable -``` - -::: - -You can connect Homarr to multiple Docker-compatible sockets by mounting each socket and listing their in-container paths, separated by commas: +Mount the Docker socket into the Homarr container: ```yaml services: @@ -116,12 +27,34 @@ services: image: ghcr.io/homarr-labs/homarr:latest volumes: - /var/run/docker.sock:/var/run/docker.sock - - ${XDG_RUNTIME_DIR}/podman/podman.sock:/var/run/podman.sock - environment: - DOCKER_SOCKET_PATHS: /var/run/docker.sock,/var/run/podman.sock + - ./homarr/appdata:/appdata ``` -For remote socket proxies, list the hostnames and matching ports in the same order: +`/var/run/docker.sock` is the default. For other in-container paths, set a comma-separated list: + +```yaml +environment: + DOCKER_SOCKET_PATHS: /var/run/docker.sock,/var/run/podman.sock +``` + +## Podman + +Homarr uses Podman's Docker-compatible API. Start the Podman socket, mount it, and include its in-container path in +`DOCKER_SOCKET_PATHS`. + +For rootless Podman: + +```sh +systemctl --user enable --now podman.socket +podman info --format '{{.Host.RemoteSocket.Path}}' +``` + +Run Homarr as the user that owns the socket. On SELinux systems, Podman may require `security_opt: [label=disable]` for +the Homarr container. Rootful Podman normally exposes `/run/podman/podman.sock`. + +## Remote endpoints + +For Docker socket proxies, list aligned hostnames and ports: ```yaml environment: @@ -129,193 +62,71 @@ environment: DOCKER_PORTS: 2375,2375 ``` -Homarr automatically discovers each comma-separated entry as a separate Docker environment. All environments are selected by default; the Docker widget lets you select one or more without any additional setup. +:::warning Plaintext Docker API + +Unauthenticated Docker TCP provides control of the Docker host. Keep a socket proxy on a private network or use TLS. -:::warning[Plaintext TCP] -Plaintext Docker TCP can grant unauthenticated control of the Docker host. Prefer a local socket, a least-privilege socket proxy on a private Docker network, or TLS. ::: -### Advanced endpoint configuration - -Most users should use the comma-separated variables above. Use `DOCKER_ENDPOINTS` only when you need custom names, TLS, or restricted capabilities. It is a JSON array where every endpoint declares its identity, transport, and capabilities: +Use `DOCKER_ENDPOINTS` for named endpoints, TLS, or restricted capabilities: ```yaml -services: - homarr: - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - ./docker-ca.pem:/run/secrets/docker-ca.pem:ro - environment: - DOCKER_ENDPOINTS: >- - [ - { - "id": "local", - "name": "Local Docker", - "kind": "docker", - "transport": { "type": "socket", "path": "/var/run/docker.sock" }, - "capabilities": ["inventory", "logs", "lifecycle", "remove"] - }, - { - "id": "remote-read-only", - "name": "Production inventory", - "kind": "docker", - "transport": { - "type": "tls", - "host": "docker.example.com", - "port": 2376, - "caPath": "/run/secrets/docker-ca.pem" - }, - "capabilities": ["inventory", "logs"] - } - ] +environment: + DOCKER_ENDPOINTS: >- + [ + { + "id": "local", + "name": "Local Docker", + "kind": "docker", + "transport": { "type": "socket", "path": "/var/run/docker.sock" }, + "capabilities": ["inventory", "logs", "lifecycle", "remove"] + }, + { + "id": "production", + "name": "Production inventory", + "kind": "docker", + "transport": { + "type": "tls", + "host": "docker.example.com", + "port": 2376, + "caPath": "/run/secrets/docker-ca.pem" + }, + "capabilities": ["inventory", "logs"] + } + ] ``` -The stable `id` keeps containers from different endpoints distinct. `name` is shown in the interface, and `kind` can be `docker` or `podman`. Every endpoint must include the `inventory` capability; optionally add `logs`, `lifecycle`, and `remove`. Homarr hides or disables actions the endpoint does not allow and also enforces the same capabilities on the server. +Each endpoint requires a stable `id`, display `name`, `kind` (`docker` or `podman`), transport, and the `inventory` +capability. Optional capabilities are `logs`, `lifecycle`, and `remove`. -Supported transports are: +| Transport | Required values | +| --------- | ----------------------------------------------------------------------------------- | +| `socket` | Absolute in-container `path` | +| `tls` | `host`, `port`, absolute `caPath`; optional `certPath` and `keyPath` for mutual TLS | +| `tcp` | `host`, `port`, and `allowInsecure: true` | -- `socket`: an absolute in-container `path` -- `tls`: `host`, `port`, and an absolute `caPath`; add both `certPath` and `keyPath` for mutual TLS -- `tcp`: `host`, `port`, and the explicit acknowledgement `allowInsecure: true` +`DOCKER_ENDPOINTS` takes precedence over the socket, hostname, and port lists. -The structured configuration refuses TCP unless `allowInsecure` is explicitly set to `true`. When `DOCKER_ENDPOINTS` is set, it takes precedence over `DOCKER_SOCKET_PATHS`, `DOCKER_HOSTNAMES`, and `DOCKER_PORTS`. +## Use in Homarr -### Managing your Docker containers within Homarr +The Docker management page lists containers from every configured endpoint and can show logs, resource use, and +permitted lifecycle actions. The Docker widget can include all endpoints or a selected subset. -Homarr allows you to interact with Docker containers running on your system. -The collapsed **Assisted Docker setup** helper optionally compares visible containers with your existing Homarr apps and integrations. Open it only when you want setup suggestions; it never blocks normal container management. Every service stays distinct by Docker endpoint and container ID, including multiple containers that use the same integration type. +Assisted setup compares discovered containers with existing apps and integrations. Discovery is read-only; creating or +updating a Homarr resource still requires confirmation. If one endpoint is unavailable, containers from healthy +endpoints remain visible. -Homarr can show a service as: +The `homarr.hide` label excludes a container. Other `homarr.*` labels can provide apps, integrations, groups, and widgets +during onboarding; see [Docker label discovery](../docker-labels). -- **Ready to connect** when its image or name matches a supported integration -- **New service** when it can be added as an app but no integration is recognized -- **Already represented** or **Linked** when an app or integration already matches -- **Address changed** when a service appears to match an integration but its reachable address has changed +## Security -Set the usual server address once, then choose whether services normally use different ports, subdomains, or paths. Homarr uses that pattern to prefill every detected service. Each suggestion has one editable URL field with the generated and Docker-reported addresses available as autocomplete options, so you can select a suggestion or type any address directly. +A Docker or Podman socket grants extensive host control. Prefer a least-privilege socket proxy when lifecycle access is +not required. -:::info[Review before changing] -Service discovery is read-only. Homarr never creates or changes an app or integration automatically. **Set up integration** opens the standard prefilled integration form, while **Create app** opens the existing Docker app form, so you can review and confirm the final setup. -::: +Homarr needs `CONTAINERS=1` for inventory and `POST=1` for standard lifecycle actions with common proxies. LSIO's proxy +can instead expose `ALLOW_START=1`, `ALLOW_STOP=1`, and `ALLOW_RESTARTS=1` while keeping `POST=0`; removal is then +unavailable. -Suggestions appear as a compact task list. Expand an item only when you want to edit its URL or inspect relevant setup statuses. Use the filters to focus on services that need attention or those already represented in Homarr. Refresh runs discovery again. Dismissed suggestions are stored in the current browser using their endpoint-qualified service identity and can be restored from the same helper. If multiple existing items could match, Homarr marks the result as ambiguous and does not choose one automatically. - -Compact status icons summarize the setup information Homarr can act on. Unknown and non-applicable runtime layers are omitted to keep the helper focused; use the integration form's connection test or the relevant board action for live diagnostics. - -If one Docker endpoint is unavailable, Homarr reports that endpoint while continuing to show services from healthy endpoints. An unavailable endpoint is not treated as an empty Docker installation. - -Each container row has an action menu with the following options: - -- **View logs** - opens a dedicated logs page with a live terminal -- **Start** - start a stopped container -- **Stop** - stop a running container -- **Restart** - restart a container -- **Remove** - remove a container -- **Add to Homarr** - create a bookmark app from the container - -You can also search and filter containers by **container** or **image** name: - -![Container and Image Search](img/container-and-image-search.png) - -#### Viewing container logs - -You can view the real-time logs of any container by selecting **View logs** from the row action menu. -This opens a dedicated page with an xterm.js terminal that streams the container's log output. - -#### CPU and Memory columns - -The Docker management table supports optional **CPU usage** and **Memory usage** columns. -These columns are hidden by default and can be toggled on from the table column visibility settings. - -#### Choosing Docker environments in the widget - -The Docker widget can show one or more configured Docker environments. Leave **Docker environments** empty to include every endpoint, which is also the default for existing widgets. Selecting one or more entries limits container and statistics requests to those endpoints. - -#### Add apps from containers - -Homarr also lets you add apps from containers. You can simply select all containers you want to add an app for and then click the `Add to Homarr` button. -This will open a dialog where you can specify the web addresses for all of them: - -![Dialog for addding apps to Homarr](img/add-to-homarr-dialog.png) - -Once you've changed the web addresses, click the `Add` button to add the apps to Homarr. -They are then available in the app list and can be used as normally added apps. - -![Apps added from containers](img/add-to-homarr-apps.png) - -### Container labels - -`homarr.hide` excludes a container from the Docker Containers widget, tools page, and onboarding discovery whenever the -label is present. - -During first-run onboarding, Homarr can also discover apps, integrations, groups, and compatible widgets from -`homarr.*` labels, with Homepage labels as a fallback. See the complete [Docker label reference](/docs/integrations/docker-labels). - -### Security - -Mounting docker sockets can be risky, as they permit full control over your docker service. -As an example, a thread actor could abuse Homarr use the socket to start, stop or delete containers on your system. - -Therefore we recommend the usage of a socket proxy, which can prohibit certain actions. -A few examples include: - -- https://github.com/linuxserver/docker-socket-proxy -- https://github.com/Tecnativa/docker-socket-proxy - -See documentation of the respective proxies on how to configure them. -Homarr may behave in unexpected ways when you use proxies. - -#### Permissions - -Homarr needs the following permissions from the Docker API: - -- Containers/Start -- Containers/Stop -- Containers/Restart -- Containers/Remove - -For socket proxies, you will need these permissions: - -- `CONTAINERS=1` -- `POST=1` - -**Caution:** `POST` access is security critical as it provides extensive capabilities to modify your docker environment. Please leave it disabled if you're concerned about this. - -As a workaround, you can use [LSIO's socket proxy](https://github.com/linuxserver/docker-socket-proxy) and set the following: - -- ALLOW_START=1 -- ALLOW_STOP=1 -- ALLOW_RESTARTS=1 - -These will work even with `POST=0`. - -You lose the ability to remove containers, but start, stop and restarts should work just fine. - -#### Connecting to Docker via Socket Proxies - -To connect to Docker via a socket proxy, you'll need to add these two environment variables in the compose file: - -- `DOCKER_HOSTNAMES=` -- `DOCKER_PORTS=` - -Refer: https://homarr.dev/docs/advanced/environment-variables/ - -You will also need to add Homarr to the network of your socket proxy. You can do it like this: - -1. Add the network to your compose file (with appropriate changes): - -```yaml -networks: - socket-proxy: - name: socket-proxy # <--- change this to the name of the network as set up by the socket proxy - external: true -``` - -2. Add the network to the homarr service in the compose file: - -```yaml -networks: - - socket-proxy -``` - -3. Finally, if it is present, remove the default docker socket connection under `volumes` in the homarr service. +Add Homarr to the proxy's Docker network and configure its service name and port with `DOCKER_HOSTNAMES` and +`DOCKER_PORTS`. diff --git a/apps/docs/docs/integrations/ical/index.mdx b/apps/docs/docs/integrations/ical/index.mdx index 475229a34..8f7293bfc 100644 --- a/apps/docs/docs/integrations/ical/index.mdx +++ b/apps/docs/docs/integrations/ical/index.mdx @@ -8,7 +8,6 @@ import { IntegrationHeader } from "@site/src/components/integrations/header"; import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; import { AddingIntegration } from "@site/src/components/integrations/adding"; import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; -import { IconZoomQuestion, IconChartBar, IconSearch } from "@tabler/icons-react"; import { icalIntegration } from "."; import { calendarWidget } from "@site/docs/widgets/calendar"; @@ -39,6 +38,5 @@ import { calendarWidget } from "@site/docs/widgets/calendar"; ]} /> -## Using the iCal integration - -The iCal integration allows you to add external calendars to Homarr. Any calendar that provides a public iCal URL can be integrated, such as Google Calendar, Apple Calendar, or Outlook. +The integration accepts any public iCal URL, including calendars published by Google Calendar, Apple Calendar, and +Outlook. diff --git a/apps/docs/docs/integrations/immich/index.mdx b/apps/docs/docs/integrations/immich/index.mdx index efe4c5106..825fff97c 100644 --- a/apps/docs/docs/integrations/immich/index.mdx +++ b/apps/docs/docs/integrations/immich/index.mdx @@ -1,6 +1,6 @@ --- title: "Immich" -description: "Self-hosted photo and video management solution" +description: "Self-hosted photo and video management." hide_title: true --- @@ -14,7 +14,7 @@ import { immichServerStatsWidget } from "../../widgets/immich-server-stats"; -### Widgets & Capabilities +### Widgets and capabilities @@ -24,34 +24,16 @@ import { immichServerStatsWidget } from "../../widgets/immich-server-stats"; ### Secrets - +`album.statistics`, `album.read`, `album.create`, `user.read`, `user.update`, `asset.read`, `asset.view`, +`asset.download`, `asset.statistics`, `server.statistics`, and `server.about`. - Select the following permissions:{" "} - album.statistics,{" "} - album.read,{" "} - album.create,{" "} - user.read,{" "} - user.update,{" "} - asset.read,{" "} - asset.view,{" "} - asset.download,{" "} - asset.statistics,{" "} - server.statistics,{" "} - server.about. - - - -), -'Create the integration in Homarr and copy the API key to there' -] -}]} /> + diff --git a/apps/docs/docs/integrations/kubernetes/index.mdx b/apps/docs/docs/integrations/kubernetes/index.mdx index 7183a9b63..bbd7fc04a 100644 --- a/apps/docs/docs/integrations/kubernetes/index.mdx +++ b/apps/docs/docs/integrations/kubernetes/index.mdx @@ -1,55 +1,33 @@ --- title: "Kubernetes" -description: "Kubernetes is a powerful container orchestration platform that automates the deployment, scaling, and management of containerized applications." +description: "Read Kubernetes resources and cluster metrics in Homarr." hide_title: true --- import { IntegrationHeader } from "@site/src/components/integrations/header"; import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; -import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; -import { IconBrandDocker, IconTool } from "@tabler/icons-react"; import { kubernetesIntegration } from "."; -Homarr provides a user-friendly Kubernetes dashboard that offers an overview of your cluster’s resources in a clear and structured interface. It allows users to view key Kubernetes objects, including `Pods`, `Services`, `Ingresses`, `Nodes`, `ConfigMaps`, `Secrets`, `Namespaces`, and `Volumes`, as well as basic metrics when the Kubernetes Metrics Server is enabled. +Homarr provides a read-only view of pods, services, ingresses, nodes, ConfigMaps, Secrets, namespaces, and volumes. +Metrics Server is optional; without it, inventory and reserved capacity remain available but live CPU and memory do not. -Docker service discovery does not convert Kubernetes resources into Homarr apps or integrations. Kubernetes remains a separate, read-only operational view, so a cluster resource is never changed or linked automatically. +## In-cluster access -:::warning[Read only] -This integration is read-only, meaning Homarr does not modify or manage cluster resources but serves as an informational tool to enhance visibility into your Kubernetes environment. -::: - -![Dashboard](img/dashboard.jpeg) - -### Prerequisites - -Before deploying Homarr in Kubernetes, ensure the following prerequisites are met: - -- Kubernetes (Version >= 1.24.0) -- Metrics Server ([install from here](https://github.com/kubernetes-sigs/metrics-server)) is optional. Without it, Homarr still shows cluster inventory, node status, and reserved capacity, and identifies live CPU and memory usage as unavailable. -- RBAC Enabled (Required for Homarr Helm chart) - -### Configuring RBAC in Helm Chart - -To enable RBAC for Homarr, configure the Helm chart values file as follows: +Enable RBAC in the Homarr Helm values: ```yaml rbac: enabled: true ``` -:::tip[What Does rbac.enabled Do?] -Enabling RBAC in the Helm chart creates the necessary Kubernetes Role-Based Access Control (RBAC) resources to allow Homarr to view various Kubernetes objects. These include: +The chart creates the service account and read-only Role/ClusterRole bindings used by Homarr. Kubernetes 1.24 or newer is +required. -- Service Account: A dedicated service account for Homarr. -- Role & RoleBinding: Grants permissions within a specific namespace to list, watch, and get pods, services, secrets, configmaps, and more. -- ClusterRole & ClusterRoleBinding: Extends the same permissions cluster-wide for additional flexibility. - ::: +## Kubeconfig contexts -### Multiple Kubernetes contexts - -When Homarr runs outside a cluster, set `KUBECONFIG` explicitly so Homarr loads the contexts from the referenced kubeconfig file or files. Mount the kubeconfig read-only and set the standard `KUBECONFIG` environment variable to its path inside the Homarr container: +When Homarr runs outside the cluster, mount a kubeconfig read-only and set `KUBECONFIG` to its in-container path: ```yaml services: @@ -60,20 +38,7 @@ services: KUBECONFIG: /app/config/kubeconfig ``` -The Kubernetes management pages include a context selector. The selected context is stored in the page URL, so each React Query cache entry and every API request remains context-specific. Resources with the same namespace and name in two contexts therefore remain separate. +The management page exposes every configured context. An unavailable context does not hide healthy contexts; a context +without Metrics Server is marked **Metrics unavailable**. -Context status is checked independently. If one context is unavailable, the selector still lists healthy contexts. A context is shown as **Metrics unavailable** when its Kubernetes API is reachable but Metrics Server is not; inventory remains available without live CPU and memory usage. - -When Homarr runs inside Kubernetes without `KUBECONFIG`, it keeps using the in-cluster service account as the single default context. - -### Homarr Dashboard Overview - -Once deployed, Homarr provides a dashboard displaying Kubernetes metrics and resource information. The main page includes: - -- Pods: Lists running and pending pods. -- Services: Shows available services and their configurations. -- Ingresses: Displays ingress rules and associated routes. -- Nodes: Provides an overview of cluster nodes and their status. -- ConfigMaps & Secrets: Lists configuration data and secrets used within the cluster. -- Namespaces: Displays all available namespaces in the cluster. -- Volumes: Shows persistent and ephemeral storage resources. +Kubernetes resources are not converted into Homarr apps or integrations during Docker discovery. diff --git a/apps/docs/docs/integrations/opnsense/index.mdx b/apps/docs/docs/integrations/opnsense/index.mdx index 9a3a2b1ee..7be1ee8d5 100644 --- a/apps/docs/docs/integrations/opnsense/index.mdx +++ b/apps/docs/docs/integrations/opnsense/index.mdx @@ -1,6 +1,6 @@ --- title: "OPNsense" -description: "OPNsense is an open-source, easy-to-use, and easy-to-build firewall and routing platform." +description: "Open-source firewall and routing platform." hide_title: true --- @@ -8,22 +8,14 @@ import { IntegrationHeader } from "@site/src/components/integrations/header"; import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; import { AddingIntegration } from "@site/src/components/integrations/adding"; import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; -import { IconHeartRateMonitor } from "@tabler/icons-react"; import { opnsenseIntegration } from "."; -import Alert from "@theme/Admonition"; import { firewallWidget } from "../../widgets/firewall"; -### Widgets & Capabilities +### Widgets and capabilities - + ### Adding the integration @@ -31,44 +23,18 @@ import { firewallWidget } from "../../widgets/firewall"; ### Secrets +Use a dedicated API-only user with **Lobby: Dashboard** and **Reporting: Traffic** privileges. + - This integration does not require full API access to the firewall. The following guide outlines the process - for creating a restricted OPNsense user with a scrambled password, designed exclusively for API access. This - ensures minimal permissions and prevents local login capability. - - ), steps: [ - "Log in to the OPNsense web interface as an administrator", - "Navigate to System → Access → Users", - "Click the + (Add) button to create a new user", - <> - Fill in the user details: -
    -
  • Username: Enter a unique name
  • -
  • Password: Leave empty
  • -
  • Scrambled Password: Enable this option
  • -
  • Full name: (Optional) Add a descriptive name
  • -
- , - <> - In Privileges section → Select the option below: -
    -
  • Lobby: Dashboard
  • -
  • Reporting: Traffic
  • -
- , - "Click Save", - "Return to the Users list", - "Find the user and click the ticket icon in the Commands column", - "Click Yes in the popup to confirm", - "A txt file will download automatically, containing: Key and Secret", - "Save this file securely—this information will only be shown once", + "Under System → Access → Users, create a user with Scrambled Password enabled.", + "Grant Lobby: Dashboard and Reporting: Traffic privileges, then save the user.", + "Use the ticket action for that user and confirm the API key download.", + "Copy the downloaded key and secret into Homarr.", ], }, ]} diff --git a/apps/docs/docs/integrations/pi-hole/index.mdx b/apps/docs/docs/integrations/pi-hole/index.mdx index d724b026d..18b52840e 100644 --- a/apps/docs/docs/integrations/pi-hole/index.mdx +++ b/apps/docs/docs/integrations/pi-hole/index.mdx @@ -8,7 +8,6 @@ import { IntegrationHeader } from "@site/src/components/integrations/header"; import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; import { AddingIntegration } from "@site/src/components/integrations/adding"; import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; -import { IconAd, IconDeviceGamepad } from "@tabler/icons-react"; import Alert from "@theme/Admonition"; import { dnsHoleSummaryWidget } from "@site/docs/widgets/dns-hole-summary"; import { dnsHoleControlsWidget } from "@site/docs/widgets/dns-hole-controls"; @@ -44,7 +43,7 @@ import { piHoleIntegration } from "."; { credentials: ["apiKey"], steps: [], - body: "Please note, that in v6 of Pi-hole you no longer specify an API key, but instead either a password or application password. We suggest to use the application password when possible.", + body: "Pi-hole v6 uses a password or application password instead of an API key. Prefer an application password.", }, { credentials: [], diff --git a/apps/docs/docs/integrations/proxmox/index.mdx b/apps/docs/docs/integrations/proxmox/index.mdx index f038dd007..e30b04260 100644 --- a/apps/docs/docs/integrations/proxmox/index.mdx +++ b/apps/docs/docs/integrations/proxmox/index.mdx @@ -1,6 +1,6 @@ --- title: "Proxmox" -description: "Proxmox is a powerful open-source virtualization platform that allows you to run virtual machines and containers." +description: "Virtual machines and containers managed by Proxmox VE." hide_title: true --- @@ -8,15 +8,12 @@ import { IntegrationHeader } from "@site/src/components/integrations/header"; import { IntegrationCapabilites } from "@site/src/components/integrations/widgets"; import { AddingIntegration } from "@site/src/components/integrations/adding"; import { IntegrationSecrets } from "@site/src/components/integrations/secrets"; -import { IconHeartRateMonitor } from "@tabler/icons-react"; import { proxmoxIntegration } from "."; -import Alert from "@theme/Admonition"; import { healthMonitoringWidget } from "@site/docs/widgets/health-monitoring"; -import { systemResourcesWidget } from "@site/docs/widgets/system-resources"; -### Widgets & Capabilities +### Widgets and capabilities @@ -26,81 +23,23 @@ import { systemResourcesWidget } from "@site/docs/widgets/system-resources"; ### Secrets +Use a Proxmox VE (`pve`) user and API token with the `PVEAuditor` role at `/` and **Propagate** enabled. PAM +authentication may not work with the API. + - The Proxmox API may not work with Linux PAM standard authentication. It is strongly recommended to use the - Proxmox VE authentication server realm when creating your API user. - - ), credentials: ["username", "tokenId", "realm", "apiKey"], steps: [ - "Navigate to the Proxmox portal, click on Datacenter", - "Expand Permissions, click on Groups", - "Click the Create button", - "Name the group something informative, like api-users", - "Click on the Permissions 'folder'", - <> - Click Add {"->"} Group Permission -
    -
  • Path: /
  • -
  • Group: group from Step 4 above
  • -
  • Role: PVEAuditor
  • -
  • Propagate: Checked
  • -
- , - "Expand Permissions, click on Users", - <> - Click the Add button -
    -
  • User name: something informative like api
  • -
  • Realm: Proxmox VE authentication server
  • -
  • Password: create a secure password for the user
  • -
  • Confirm Password: re-enter the password
  • -
  • Group: group from Step 4 above
  • -
- , - "Expand Permissions, click on API Tokens", - <> - Click the Add button -
    -
  • User: user from Step 8 above
  • -
  • Token ID: something informative like the application or purpose like homarr
  • -
  • Privilege Separation: unchecked
  • -
- , - "Copy the Secret that is shown in Step 10 because it is only shown once", - "Go back to the 'Permissions' menu", - <> - Click Add {"->"} API Token Permission -
    -
  • Path: /
  • -
  • API Token: select the API token created in Step 10
  • -
  • Role: PVE Auditor
  • -
  • Propagate: Checked
  • -
- , + "Create a Proxmox VE user or group and grant PVEAuditor at / with Propagate enabled.", + "Create an API token for that user. Disable privilege separation to inherit the user permission, or grant the token the same PVEAuditor permission.", + "Copy the token secret when Proxmox displays it and enter the user, realm, token ID, and secret in Homarr.", ], body: ( - <> - - Sometimes you'll also find the api@pve!homarr format, within Homarr you'll have to split it up - into: - -
    -
  • - Username: api -
  • -
  • - Realm: pve -
  • -
  • - Token ID: homarr -
  • -
- +

+ For api@pve!homarr, use username api, realm pve, and token ID{" "} + homarr. +

), }, ]} diff --git a/apps/docs/docs/management/api/index.mdx b/apps/docs/docs/management/api/index.mdx index df5ac4e32..7da2c975d 100644 --- a/apps/docs/docs/management/api/index.mdx +++ b/apps/docs/docs/management/api/index.mdx @@ -6,134 +6,52 @@ tags: - Interface --- -Using the Homarr API, you can interface with the application with your own code and business logic. -It enables you to trigger almost all actions that you can perform from the Homarr UI. -With the API, you can build resilient systems that automatically update Homarr with data - for example syncing it with -your deployments in a cluster or dynamically adding integrations depending on how many replicas you run. +Homarr exposes OpenAPI and tRPC endpoints for automation. Open the generated specification under +**Management → Tools → API** or use the [interactive API reference](/api-reference). -This page is language-neutral, and you must implement the API on your own in your desired language. -It requires you to know your programming language well and have a basic understanding of HTTP, JSON and networking. -You can test out API endpoints using any OpenAPI client - for example [Yaak](https://yaak.app/). - -## Opening the API specification - -The specification is implemented according to the OpenAPI standard. -To access the documentation, you'll need to spin up an instance of Homarr. -Navigate to `Management` > `Tools` > `API`. -You can copy the JSON url into your OpenAPI client or try out the endpoints directly from your browser. - -Alternatively, you can [open the full interactive API reference](/api-reference) directly in your browser. +![Homarr's API documentation page](../img/api.png) ## Authentication -Many endpoints will require you to authenticate. At the top of the API reference, you'll find a button to authenticate yourself with an API key. -You can obtain API keys from the "Authentication" tab at the top of the page. -API keys will not expire and can be used indefinitely. -When you create a key, its one-time value is shown inline above the key table. Copy it before closing the notice; the -creation action remains disabled until the value has been acknowledged. Deletion uses a two-click inline confirmation -instead of opening a separate dialog. +Create an API key from the **Authentication** tab. Its value has the form `.` and is shown once. -### API Key Format +Send it in the `ApiKey` header: -API keys are provided in the format `.`. When making requests, include the key in the `ApiKey` header: - -``` -ApiKey: abc123def456.xyz789tokenvalue... +```sh +curl -H 'ApiKey: .' https://homarr.example.com/api/health/live ``` -### Supported Endpoints +The same header authenticates tRPC requests under `/api/trpc`. Without a key, browser requests can use the Homarr +session cookie. -API key authentication works with both endpoint types: +API keys do not expire automatically and act as the user that created them. Every request uses that user's group and +resource permissions. -| Endpoint Type | Path Pattern | API Key Support | -| ------------- | --------------- | --------------- | -| OpenAPI | `/api/...` | ✅ Supported | -| tRPC | `/api/trpc/...` | ✅ Supported | +## Permission behavior -If no API key is provided, Homarr falls back to session cookie authentication (for browser-based access). +Unauthorized operations return `FORBIDDEN`. List endpoints filter records on the server when resource-specific access +applies. -### Usage Examples +App catalog endpoints such as `app.all`, `app.getPaginated`, and `app.search` require **Modify all apps** because they +include internal URLs. Use `app.selectable` for the reduced board-picker fields. -**OpenAPI endpoint:** +Integration list and search endpoints return only integrations the key owner can access. Check each integration's +`hasUseAccess` and `hasInteractAccess` fields before reading data or invoking actions. -```bash -curl -H 'ApiKey: .' http://localhost:7575/api/health/live -``` +## Board automation -**tRPC endpoint:** +The API can create, duplicate, rename, delete, and configure boards; manage board content; and set desktop or mobile home +boards. -```bash -curl -H 'ApiKey: .' http://localhost:7575/api/trpc/app.all -``` +Each board has exactly one Mobile and one Base layout. Mobile uses breakpoint `0`; all breakpoints are unique. Custom +layouts can use any other breakpoint, and Homarr selects the highest breakpoint that fits the viewport. Preserve layout +roles and use the canonical layouts returned by save operations, including generated IDs. -### Use Cases +Creating or changing an integration-backed widget requires use access to each newly selected integration. -API key authentication enables programmatic access for: +## Docker targets -- Automation scripts and CI/CD pipelines -- Third-party integrations -- Custom dashboards and monitoring tools -- Container orchestration systems that need to sync app definitions - -## Permissions - -API keys act as the user that created them, so every request is subject to that user's group -permissions. A call that the user is not allowed to make returns `FORBIDDEN`, and list endpoints -return only the records the user may see rather than failing. - -### App endpoints require app management access - -`GET /api/apps`, `GET /api/apps/paginated` and `GET /api/apps/search` (tRPC `app.all`, -`app.getPaginated`, `app.search`) require the **modify all apps** permission. They previously -returned the full app catalogue — including internal URLs — to any authenticated user. - -If a script that used to work now returns `FORBIDDEN`, grant **modify all apps** to a group the key -owner belongs to, or switch to `GET /api/apps/selectable`, which returns the reduced fields used by -board pickers. - -### Integration endpoints are filtered per key - -`integration.all`, `integration.allThatSupportSearch`, `integration.allOfGivenCategory` and -`integration.search` filter server side. Without a global integration permission, a key only -receives the integrations its owner has been granted access to, so responses may contain fewer -records than before rather than returning an error. `integration.search` applies its `limit` after -filtering, so a scoped key still receives a full page of results. - -Each returned integration carries a `permissions` object — check `hasUseAccess` before reading data -and `hasInteractAccess` before performing actions; `false` means the key owner lacks that level for -that integration, not that the call failed. - -## Board Automation - -The OpenAPI and MCP APIs include board management endpoints for common automation workflows: - -- Create, duplicate, rename and delete boards -- Change board visibility -- Update board visual and behavior settings -- Set desktop and mobile home boards for the current user -- Configure global board defaults such as public home boards and status behavior - -Creating, duplicating, or reconfiguring a widget validates its integration selection on the server. The caller needs -use access for each newly linked integration; unchanged links remain editable through normal board permissions. - -Board layout responses identify each layout with a `mobile`, `base`, or `custom` role. Mobile and Base are protected. Layout-saving clients must preserve existing roles, keep Mobile at breakpoint `0`, keep Base as the highest breakpoint, and use unique custom breakpoints between them. The layout save operation returns the canonical saved layouts, including server-generated IDs for new custom layouts. A non-Base layout can be regenerated from Base with the protected reset operation. - -The internal `board.getManageOverview` tRPC query returns compact board previews limited to 12 layout rows by default. Callers may provide `previewRowLimit` from 1 through 48; `fullPreview: true` requests the server's 48-row maximum. - -Use the interactive API reference to inspect the exact request body for each endpoint under the `boards` and `settings` tags. - -## Docker action payload migration - -Docker lifecycle and removal actions now identify each container with both its Docker endpoint and container ID. This is a -breaking change for tRPC and MCP clients that previously sent an `ids` array to the start, stop, restart, or remove action. - -Replace the old payload: - -```json -{ "ids": ["container-id"] } -``` - -with endpoint-qualified targets: +Docker actions identify both the configured endpoint and the container: ```json { @@ -141,57 +59,21 @@ with endpoint-qualified targets: } ``` -Read `endpointId` and `id` from `docker.getContainers` (MCP tool `docker_getContainers`) immediately before the action. -Pass those pairs unchanged to `docker.startAll`, `docker.stopAll`, `docker.restartAll`, or `docker.removeAll`; their MCP tool -names use underscores, such as `docker_restartAll`. Endpoint qualification prevents identical container IDs on different -Docker or Podman endpoints from targeting the wrong service. +Read both values from `docker.getContainers` immediately before calling `docker.startAll`, `stopAll`, `restartAll`, or +`removeAll`. The endpoint ID prevents collisions between Docker or Podman hosts. -`docker.getContainers` also accepts an optional `endpointIds` array. Omit it or pass an empty array to query every configured -Docker environment, or pass one or more IDs returned by `docker.getEndpoints` to query only those Dockerode clients. The -Docker widget uses the same behavior for its environment selector. +`docker.getContainers` accepts optional `endpointIds`. Omit it or pass an empty array for every configured endpoint. -## Partial integration failures +## Partial upstream failures -Multi-integration widget queries keep data from integrations that remain available. Calendar and media-server results include -an optional `error` on a failed integration; media-request responses expose a `failedIntegrations` array, and the latest -requests endpoint returns its items in `requests`. When every selected integration fails, the query returns an error instead -of a partial response. +Queries that combine several integrations can return healthy data alongside failure metadata. The exact response shape +depends on the endpoint; inspect the generated schema instead of assuming a common `error` field. When every selected +integration fails, the query returns an error. -Other widgets use the same settlement pattern with endpoint-specific shapes: a failed integration may appear as a named -fallback row, in a failure array, or be omitted while healthy results remain. Widget pages should identify the shape they -render rather than assuming every query exposes an `error` field. +## Custom Widget resources -### Saving dashboard layouts +Authenticated administrators can retrieve the current Custom Widget authoring prompt, schema, component catalog, skill, +and focused references under `/api/custom-widgets/`. -The dashboard editor saves item positions and sections as one board update. -Canvas height follows its content automatically and does not require a separate API setting. -Responsive layouts store optional left and right gutter widths from zero to three columns. -Gutter columns are reserved from the layout's total column count, and changing them reflows affected items. - -## Get Custom Widget authoring resources - -Custom JSX v2 provides focused HTTP discovery endpoints: - -- `GET /api/custom-widgets/authoring-prompt` returns the current prompt plus MCP and HTTP resource identifiers. -- `GET /api/custom-widgets/schema` returns the canonical widget JSON Schema. -- `GET /api/custom-widgets/components` returns the release-matched static component catalog. -- `GET /api/custom-widgets/skill` returns the concise live `SKILL.md`, a named-reference index, and installation metadata. -- `GET /api/custom-widgets/reference-schema`, `/reference-runtime`, and `/reference-security` return one authoring - reference at a time. - -Retrieve the schema, component catalog, references, and examples only when needed. Preview creation returns separate -`queries` and `actions` evidence lists. Each action includes its HTTP method, invocation parameters, minimum board -permission, confirmation, and invalidated query IDs so clients can simulate and verify mutations before persistence. - -For an evidence-driven JSX correction, `customWidget_previewReviseTemplate` accepts only the preview session, -optional expected revision, and `template` or `templateLines`. It inherits and fully revalidates the manifest, advances -the session revision, and returns fresh query/action lists without echoing sources, requests, options, or secrets. -`customWidget_createFromPreview` requires current-revision evidence for every query and action; simulated action checks -count as evidence without executing the mutation. - -MCP clients can call `customWidget_findComponents` with a capability query for a small release-matched component subset -instead of retrieving the complete component catalog. - -Call `customWidget_configurationRequestUser` to create a temporary API source setup URL where the user can confirm their server URL and enter credentials. Do not construct or save this URL. - -Authenticated tRPC and MCP procedures support definition management, validation, previews, template patches, and credential writes. An exported definition does not contain credentials. +Use [Custom Widget agent authoring](../custom-widgets/agent-authoring) for the lifecycle and +[MCP](../mcp) when the client supports Model Context Protocol. diff --git a/apps/docs/docs/management/apps/index.mdx b/apps/docs/docs/management/apps/index.mdx index 060e3639e..7e95ce047 100644 --- a/apps/docs/docs/management/apps/index.mdx +++ b/apps/docs/docs/management/apps/index.mdx @@ -7,61 +7,39 @@ tags: - Ping --- -Apps are the building blocks of your Homarr board. -Most of the time they are a simple link to a website, but used on your board they also support a simple ping to check if your service is up. -Apps are used in the bookmark and app widget. +import { AppFlowDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams"; -## Create an app +An **app** is a saved shortcut used by the App and Bookmarks widgets. It contains a name, destination, icon, and +optional status-check address. -To create an app you can click on the button on the top right of the apps management page: +![The Apps management page](../img/apps.png) -![New app button](./img/new-app-button.png) +## How an app is used -Next, you'll need to fill out the required fields to configure the app: + -![New app form](./img/new-app-form.png) +## Configuration -### Name +Create and manage apps under **Management → Apps**. -The name must be at least one character long and can be chosen freely. +| Field | Purpose | +| ----------- | ---------------------------------------------------------------------------------------- | +| Name | Label shown on the board | +| Icon URL | Direct image URL, icon-library result, or uploaded image | +| Description | Optional tooltip | +| URL | Destination opened from the board; custom URI schemes are supported except `javascript:` | +| Ping URL | Optional HTTP(S) address used for status checks when it differs from the destination | -### Icon URL +An app can be linked to an [integration](../integrations). Integration widgets then use the app as their destination +when they provide a link to the service. -This is the URL to the icon that will be displayed on the app widget. -You can paste a direct HTTP(S) URL to an image, search the included icon repositories by name, or upload a local file through the upload button. The app name is pre-filled as the initial library search when no image is selected. Local images appear first, followed by SVG icons and other formats. Direct image URLs are previewed, used as entered, and are not searched in the icon repositories. +See [Icons](/docs/advanced/icons) for icon sources and uploads. -![Icon URL](./img/app-icon-url.png) +## Permissions -### Description +- `app-create` creates apps. +- `app-modify-all` lists and edits every app. +- `app-full-all` also deletes and uses every app. +- `app-use-all` allows using every app on boards without granting management access. -An optional description that can be shown as tooltip on the app widget. - -### URL - -The URL to the website you want to link to. Clicking on the app widget or bookmark will open this URL. - -You can also use custom URI schemes such as `vscode://file/path`, `microsoft-edge:https://example.com`, or `myapp://open` to link to local applications or third-party programs. We trust that you know what you are doing — only `javascript:` URIs are blocked for security reasons. - -### Ping URL - -When you want to use another url for the simple status check you can set it here. -This will allow you to set a different URL for the ping than the URL that is opened when clicking on the app widget. -It's useful when you want to ping the service internally for example with a custom ip but open the website externally. -Note that the ping URL only accepts `http://` and `https://` URLs — custom URI schemes are not supported for pings. - -## List of apps - -On the apps management page you find all apps that exist in your Homarr instance. Search by name or URL, open an app -directly, or use its row actions to edit and delete it. A filtered search can be cleared without leaving the page. - -### Accessing the page - -The `/manage/apps` page is reachable when you can manage all apps (`app-modify-all`) or create apps (`app-create`): - -- **Manage all (`app-modify-all`)**: the full list of apps is shown and searchable, and each row can be edited. -- **Create only (`app-create`)**: the page shows an empty "create an app" state instead of the list, so the names and - URLs of existing apps are never disclosed. The create action is still available. -- **Neither**: the page is not reachable and returns a not-found page. - -Creating an app requires `app-create`, editing requires `app-modify-all`, and deleting requires `app-full-all`; -board permissions are not required. +Users with only `app-create` can open the page and create an app, but do not receive the existing app list. diff --git a/apps/docs/docs/management/assistant.mdx b/apps/docs/docs/management/assistant.mdx index b78473da0..ade26b418 100644 --- a/apps/docs/docs/management/assistant.mdx +++ b/apps/docs/docs/management/assistant.mdx @@ -6,72 +6,53 @@ tags: - Administration --- +import { AssistantFlowDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams"; + # Assistant -Assistant can answer questions and manage Homarr for you. It uses the signed-in user's permissions and asks for -approval before making changes. +Assistant answers questions and operates Homarr through the signed-in user's permissions. Read-only tools can run +automatically; changes require approval by default. -![Assistant conversation with suggested prompts](/img/assistant/conversation.png) +![The Assistant management page](./img/assistant.png) -## Set it up +## Request flow -Open **Management → Assistant**. + -![Assistant provider, credentials, and model configuration](/img/assistant/configuration.png) +## Configuration -1. Select a provider and check its API URL. -2. Enter an API key when required, then save the connection. -3. Refresh the model list and select a model. -4. Enable the assistant and save. +Under **Management → Assistant**, select a provider, configure its API URL and key when required, select the default +model, and enable Assistant. Users can choose another available model for a conversation. -Choose a provider preset or use **Custom endpoint** with an OpenAI-compatible Chat Completions API. The -[Homarr provider](../workshop/homarr-provider) is the default and needs no administrator API key. The Homarr team pays -for a limited number of Assistant uses for each user every day; users sign in to the Community Workshop to use them. +Provider presets cover common APIs. **Custom endpoint** accepts an OpenAI-compatible Chat Completions API. For a model +server outside the Homarr container, use a hostname that the container can resolve instead of `localhost`. -:::info Local model servers +The [Homarr provider](../workshop/homarr-provider) is available through the Community Workshop without an administrator +API key and has a daily request allowance. -Inside a container, `localhost` means the Homarr container. Use the model server's container name, local DNS name, or -host gateway address. +## Access -::: +Open Assistant from the user menu, with `Shift+A`, from search with `Cmd/Ctrl+/`, or through the +[Assistant widget](../widgets/assistant). -## Use it +Assistant can work with boards, apps, integrations, widgets, Custom Widgets, and supported connected services. Mention +Homarr resources with `@`; the model loads additional live context only when needed. -- Select **Assistant** in the user menu or press `Shift + A`. -- Press `Cmd/Ctrl + /` to ask from search, or use `Cmd/Ctrl + K` and choose the Assistant fallback. -- Add the [Assistant widget](../widgets/assistant) to a board. +Conversations are stored per user and can be searched, renamed, exported, or deleted. -The assistant can work with boards, apps, integrations, widgets, Custom Widgets, and connected services. Use `@` to -add Homarr items as context, `/` for shortcuts, and the paperclip for supported files. +## Permissions and data -Use **Conversations** to search, switch, rename, export, or delete threads. +- Every tool call uses the current user's Homarr permissions. +- Automatic approvals apply only to the current conversation and reset when switching conversations. +- Provider keys and custom headers are encrypted and are not returned to the browser. +- Prompts, attachments, tool definitions, and tool results are sent to the selected model provider. -Each request includes the user's name, current page and board, home board, server time, browser time zone, and only -explicitly mentioned Homarr entities. Live status is fetched only when needed. The full Homarr tool catalog remains -available server-side, while the model receives a small relevant subset and can discover another capability on demand. - -When web search is enabled, Assistant uses bounded search context and prefers primary documentation. Custom Widget -authoring starts with a compact skill and template validator, then discovers schema, preview, reference, and component -tools only when the task needs them. A response-driven JSX correction revises the existing preview without resending -its manifest; Homarr then requires fresh query and simulated-action evidence for that preview revision before saving. - -## Permissions and privacy - -- Read-only actions can run automatically. Changes require approval by default. Automatic approvals apply only to the - current conversation, turn off when you switch conversations, and never answer questions for you. -- Homarr permissions apply to every tool call and mentioned item. -- API keys and custom headers are encrypted and never returned to the browser. -- Conversations are stored per user and can be exported or deleted. - -Prompts, attachments, tool definitions, and tool results are sent to the selected model provider. Review that -provider's privacy policy before enabling the assistant. +See [MCP](./mcp) to connect an external AI client and +[Custom Widget agent authoring](./custom-widgets/agent-authoring) for widget generation. ## Troubleshooting -- **No models found:** check the base URL, model discovery path, and API key. You can enter a model ID manually. +- **No models found:** check the API URL, discovery path, and API key, or enter a model ID manually. - **Assistant is unavailable:** enable it and save the configuration. -- **Tool calls stop:** select a model that supports streaming and tool calls. -- **Local endpoint is unreachable:** check container networking and the server's listen address. - -See [MCP](./mcp) for external AI clients and [Custom Widget agent authoring](./custom-widgets/agent-authoring) for the -widget authoring workflow. +- **Tool calls stop:** use a model that supports streaming and tool calls. +- **Local endpoint is unreachable:** check container DNS, routing, and the model server's listen address. diff --git a/apps/docs/docs/management/backup.mdx b/apps/docs/docs/management/backup.mdx index 7b0e60077..1c47291d3 100644 --- a/apps/docs/docs/management/backup.mdx +++ b/apps/docs/docs/management/backup.mdx @@ -6,78 +6,34 @@ tags: - Data --- -# Backup & Restore +# Backup and restore -Homarr provides a built-in backup and restore system for **SQLite** instances. You can export your entire database - including apps, integrations, boards, users, and encryption keys - as a ZIP archive, and restore it on the same or a different Homarr instance. +Administrators using SQLite can export and restore the complete Homarr database under +**Management → Tools → Backup**. MySQL and PostgreSQL installations must use their database-native backup tools. -:::warning +![The Backup and restore management page](./img/backup.png) -Backup and restore is only available when using the **SQLite** database driver. MySQL and PostgreSQL instances do not show this page. +## Export -::: +The ZIP contains: -## Accessing the Backup Page +| File | Contents | +| --------------- | ----------------------------------------------------------- | +| `db.sqlite` | Apps, integrations, boards, users, settings, and other data | +| `metadata.json` | Homarr version, backup timestamp, and encryption metadata | -Navigate to `Management` → `Tools` → `Backup`. You must have **admin** permissions to access this page. +Export requires typing `I understand`. Store the ZIP as sensitive data: it contains the database and the material +needed to restore encrypted integration credentials. -## Exporting a Backup +## Restore -![Export database card with the Download Backup action](/img/backup/export-database.png) +Select a Homarr backup ZIP. The browser previews entity counts, board names, and required database migrations before +the archive is uploaded. -Click the **Export** button in the export card. You'll be prompted to type `I understand` to confirm. Once confirmed, a ZIP file downloads containing: +Restoring replaces the current SQLite database and cannot be undone. After a successful restore, the Next.js process +restarts and the page reloads when Homarr is ready. -| File | Description | -| --------------- | ------------------------------------------------------------------- | -| `db.sqlite` | Full SQLite database with all entities | -| `metadata.json` | Backup metadata: Homarr version, creation timestamp, encryption key | +A backup can be restored on another Homarr instance. When its `SECRET_ENCRYPTION_KEY` differs, Homarr re-encrypts stored +integration secrets for the target instance. Version metadata is used to apply compatible migrations. -The backup contains the complete database. It includes Custom Widgets and all other Homarr configuration. - -## Restoring a Backup - -![Restore database card with the backup ZIP drop zone](/img/backup/restore-database.png) - -### 1. Upload - -Drag and drop or select a `.zip` backup file. The import card validates that the file contains a valid `db.sqlite` and metadata. - -### 2. Preview - -Before restoring, Homarr uses **sql.js WASM** to analyze the backup directly in your browser. You'll see: - -- **Entity counts** - how many apps, integrations, boards, users, etc. are in the backup -- **Board names** - which boards will be restored -- **Migration status** - Drizzle migrations are applied in-browser with a visual timeline showing each migration step - -### 3. Confirm - -Type `I understand` to acknowledge that restoring will replace your current database. This cannot be undone. - -During first-run onboarding, the database is still empty, so the restore preview goes directly to **Restore Database** -without the extra typed confirmation. After Homarr restarts, onboarding opens the restored default home board. - -### 4. Restore - -The backup ZIP is sent to the server, validated, and applied. After a successful restore: - -- **The Next.js server restarts automatically** to reload the new database state -- Nginx and Redis (if running in Docker) stay up - only the Next.js process restarts -- The page reloads once the server is ready - -## Cross-Instance Restore - -You can restore a backup from one Homarr instance onto another. Homarr handles: - -- **Encryption key re-encryption** - If the target instance has a different `SECRET_ENCRYPTION_KEY`, integration secrets are decrypted with the old key and re-encrypted with the new one during import -- **Version compatibility** - Backups include the Homarr version they were created with. Backward compatibility is maintained for older backup formats - -## Backup During Onboarding - -When setting up a new SQLite Homarr instance, the onboarding flow includes a **Restore from SQLite backup** step. You can upload a backup ZIP directly during onboarding to skip manual setup. - -## Security - -- Export requires admin permissions -- The `I understand` confirmation dialog prevents accidental exports and overwrites -- Backups contain encrypted integration secrets - they cannot be read without the `SECRET_ENCRYPTION_KEY` -- Import only works on SQLite instances - the API routes refuse requests from MySQL/PostgreSQL instances +The same restore flow is available during first-run onboarding, before the target database contains user data. diff --git a/apps/docs/docs/management/boards/img/board-edit-mode.png b/apps/docs/docs/management/boards/img/board-edit-mode.png deleted file mode 100644 index 568e42253..000000000 Binary files a/apps/docs/docs/management/boards/img/board-edit-mode.png and /dev/null differ diff --git a/apps/docs/docs/management/boards/img/board-view-mode.png b/apps/docs/docs/management/boards/img/board-view-mode.png deleted file mode 100644 index bf9e51223..000000000 Binary files a/apps/docs/docs/management/boards/img/board-view-mode.png and /dev/null differ diff --git a/apps/docs/docs/management/boards/img/keyboard-tile-editing.png b/apps/docs/docs/management/boards/img/keyboard-tile-editing.png deleted file mode 100644 index d650821fc..000000000 Binary files a/apps/docs/docs/management/boards/img/keyboard-tile-editing.png and /dev/null differ diff --git a/apps/docs/docs/management/boards/img/layout-settings-custom-rails.png b/apps/docs/docs/management/boards/img/layout-settings-custom-rails.png deleted file mode 100644 index 7284c5831..000000000 Binary files a/apps/docs/docs/management/boards/img/layout-settings-custom-rails.png and /dev/null differ diff --git a/apps/docs/docs/management/boards/index.mdx b/apps/docs/docs/management/boards/index.mdx index 89f061f1e..762563acd 100644 --- a/apps/docs/docs/management/boards/index.mdx +++ b/apps/docs/docs/management/boards/index.mdx @@ -9,473 +9,86 @@ tags: - Layout --- -import iconColorImage from "./img/icon-color.png"; -import itemRadiusImage from "./img/item-radius.png"; -import layoutSettingsImage from "./img/layout-settings.png"; -import layoutSettingsCustomRailsImage from "./img/layout-settings-custom-rails.png"; -import boardViewModeImage from "./img/board-view-mode.png"; -import boardEditModeImage from "./img/board-edit-mode.png"; -import keyboardTileEditingImage from "./img/keyboard-tile-editing.png"; +import { BoardLayoutsDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams"; -Each dashboard is called a "board". -You can create as many boards as you want. -Boards can be restricted to user groups. -A user may also have a "home board" which they will see at the root path (e.g. my-homarr.com or my-homarr.com/boards). -Other boards can be viewed by direct links (e.g. my-homarr.com/boards/smart-home) or via the management pages. -The management page includes a compact structural preview of each board's Base layout so you can recognize it before -opening it. Containers include their visible widgets and app icons instead of appearing empty. +A **board** is a dashboard page containing apps, widgets, and Containers. Its name is unique and forms the board URL. +Boards can be public or restricted to users and groups. -Names of boards must be unique because this will be used in the URL to load the desired board. +![The Boards management page](../img/boards.png) -Press `Shift+C`, or select **Switch board** from the user menu, to open the board switcher. It shows structural -previews of every board you can access, with your current board at the end. Home-board markers and creator avatars -match the board management view. Use the search field at the top, or simply start typing, to filter by name. Use the -arrow keys to move through the results and press `Enter` to open the selected board. +Create, duplicate, open, and delete boards under **Management → Boards**. Press `Shift+C` from a board to open the +board switcher. -## Create a new board +## Responsive layouts -Select **New board** on the boards management page. The creation form expands in the page, so you can enter the board -details without opening a dialog or leaving the board list. The availability of the board name is checked as you type. + -The board menu also keeps duplication in context: select **Duplicate board**, choose the new name in the form below that -board, and create the copy without navigating to a separate page. +Mobile and Base are protected layouts. New boards use three Mobile columns; Base uses the column count selected at +creation. Additional layouts use unique breakpoints. Homarr selects the layout with the highest breakpoint that fits +the current viewport. -### Name - -The name must not include any special characters and must be at least one character long. -Underscores and hyphen-minus are allowed. - -### Column count - -The column count defines how many fixed-width cells are available in each row. -One cell contains a `200 × 200` logical-pixel tile. -Homarr scales the whole board uniformly instead of changing widget proportions, and always fits it to the available width without horizontal scrolling. -The main canvas and enabled rails stay at least one viewport tall, and the canvas grows automatically while you drag or resize items near its lower edge. - -### Public - -This will enable public access for everyone - regardless of whether they are logged in or not. -This can be really useful if you want to have public boards in your company or for family and friends. -Modifications for public boards must be allowed explicitly using user groups and their permissions. - -Deleting a board from the management list uses an inline safeguard. Select **Delete**, then select **Confirm** in the -same menu item. No separate confirmation dialog is opened. - -## Board settings - -You navigate to the board settings by clicking on these three dots: - -![](./img/navigate-to-settings.png) - -Alternatively, you can also navigate from the board page itself using the cog icon at the top right: - -![](./img/navigate-to-settings-2.png) - -All board settings are edited on a single page. Click the **Save changes** button in the save bar at the bottom to apply them, or **Discard** to restore the last saved values. The save bar only appears when you have unsaved changes. Access control and the Danger zone are independent sections and are applied immediately. - -### General - -#### Page title - -This is the title that will be visible at the top left in the navigation bar: - -![](./img/page-title.png) - -This field is optional and Homarr will fall back to "Homarr" if nothing is set. - -#### Meta title - -This is the secondary title of the page that is not directly visible in the page itself. -Browser will use it to set the title of tabs: - -![](./img/meta-title.png) - -Homarr will fall back to the board name and a suffix if nothing is set. - -#### Logo image URL - -This is the URL that is used for the image at the top left. -Homarr will fall back to the Homarr logo if nothing is set. - -#### Favicon image URL - -This is the URL that is used for the favicon in the tab title. -Homarr will fall back to the Homarr logo if nothing is set. - -### Layout - -In this section you can configure the different responsive layouts. Homarr selects the layout with the highest breakpoint that is not wider than the current screen, then scales its complete fixed-size canvas uniformly. - -Board settings showing protected Mobile and Base responsive layouts with rail controls - -The layout cards show the representative geometry used for planning. This current example also shows a custom layout -with both fixed rails enabled; the rails reserve columns and the remaining canvas reflows automatically. - -Board layout settings with a custom layout and both fixed rails enabled - -Every board has two protected layouts. Creating a board adds **Mobile** at `0px` with three columns and **Base** at -`768px` with the column count you choose. Both layouts can be edited, but neither can be removed. - -Every `1 × 1` tile has a `200 × 200` logical-pixel content area. -The `24` logical-pixel gap between tiles is separate from that size. -A `2 × 1` tile therefore contains two fixed cell widths plus the gap between them. -Widgets see their logical size, while the board's visual scale makes the complete layout larger or smaller. -When fitting below 100%, Homarr keeps widget typography and control density at their normal readable size. -On larger canvases, the complete board grows together like browser zoom. -The complete canvas always fits the available width and never adds horizontal board scrolling. - -- **Mobile** starts at `0px` and uses three columns on new boards. -- **Base** is the main layout and starts at `768px` on new boards. - -Mobile and Base can be renamed and their column counts can be changed, but they cannot be removed. Mobile has no fixed -rails; rail configuration is available only on Base and custom layouts. You can add removable custom layouts at any -unused breakpoint above Mobile. - -Each layout stores independent positions and sizes. Moving or resizing a widget while editing Mobile does not move it in -Base or any custom layout. New custom layouts start from Base's current column count and rail widths; Homarr chooses an -available breakpoint, and you can then change the breakpoint, columns, and rails. - -Older or incomplete boards are repaired automatically. A board with no layouts receives Mobile at `0px` with three -columns and Base at `768px` with ten columns. A board with one layout keeps it as Base and receives a generated Mobile -layout. When protected roles are missing from a board with multiple layouts, the narrowest becomes Mobile, the widest -becomes Base, and intermediate layouts become custom. Once roles exist, breakpoint changes do not reassign them. -Duplicate breakpoints are normalized without discarding saved positions. - -Use **Reset from Base** on Mobile or a custom layout to replace all of its positions and sizes with a newly generated version of Base. The layout's name, breakpoint, and column count are kept. - -The canvas is at least one window tall, even when it is empty. -Its left and right edges are hard drag boundaries, while its bottom edge extends automatically as a tile is dragged or resized downward. -Nested Containers keep their own resizable bounds. -New items use their widget's default size and new Containers use a useful `4 × 3` size when space allows. - -#### Name - -The name of the layout can be chosen freely. It is only used for management and is not displayed on the board. - -#### Column count - -The total number of columns in the layout. Changing it projects the saved positions and sizes into the new grid width without overlap. - -#### Fixed rails - -Each responsive layout can enable a fixed left rail, a fixed right rail, or both. -Set a rail width to zero to disable it for that layout. -Choose a width from one to three columns with the three-step slider. -The preview shows how much space remains for the main canvas. - -Rail columns are reserved from the layout's total column count. -For example, a 12-column layout with a two-column left rail leaves ten columns for the canvas. -The combined rail widths cannot consume the final main-canvas column. -Enabling or widening a rail reflows canvas items into the remaining columns. -Disabling a rail moves its contents back into the next available canvas positions. - -Rails fill the available window height and remain fixed while the page scrolls. They do not grow or scroll independently. -Apps, widgets, and Containers inside them still use the same fixed `200 × 200` cells and can be rearranged in edit mode, where each rail shows its name and boundary. - -#### Breakpoint - -The minimum screen width where the layout is used; a layout is eligible at its breakpoint and above. Mobile is fixed at -`0px`. Every other breakpoint must be unique, but Base and custom layouts can be ordered at any width. Homarr uses the -eligible layout with the highest breakpoint, regardless of its role. -When the initial viewport is not available, Homarr uses its remembered viewport information, client hints, or User-Agent -fallback to select a layout. - -#### View and edit modes - -View mode renders a static board without executing the drag-and-drop editor. -After the board is interactive, Homarr prepares the editor in the background for users who can modify it. -Entering edit mode keeps the static board visible until that preparation finishes, then enables collision-aware movement and resizing. -Collapsed Containers are expanded while editing so their contents and controls are reachable. - -A Homarr board in view mode with the dashboard canvas and static widgets visible - -Widget content is inert in edit mode, so dragging from the inert widget area moves the tile instead of activating the widget; -settings and other controls remain usable in the compact header above the tile. -A single compatible collision can swap two items when both resulting placements fit, including different-sized or lateral moves. -For other collisions, or when a tile grows into occupied space, nearby tiles are compacted out of the way and collision chains reflow. -The visible corner controls provide a 44-pixel resize target, and edge controls appear on hover for horizontal or vertical resizing. -Resize handles stop at the tile's minimum allowed size while the pointer is still moving. -Use the pencil button in the board header to enter edit mode; click it again to save. If you leave the page with unsaved -changes, Homarr asks whether to discard them. If the editor cannot load, the board remains in view mode. - -Board in edit mode with the board header controls and editable dashboard tiles visible - -While edit mode is active, **Add board content** opens a menu for adding a widget, app, integration, or Container. The -available actions respect the current user's permissions. Widget setup offers the main canvas, enabled rails, and existing -Containers as destinations before the widget is created, so the common flow does not require a second move step. - -Hold `Ctrl` on Windows or Linux, or `⌘` on macOS, while clicking board items to select several at once. The selection -toolbar can move the complete selection to another canvas, rail, or Container, delete it with an undo option, or clear the -selection. A short tip appears after entering edit mode as a reminder of the modifier key. A move is applied only when every -selected item fits in the destination. - -The widget editor also lists its selected integrations. Users with full access can choose **Edit connection** to test, -diagnose, and repair an integration without leaving the board. A successful repair refreshes the affected widget; the -saved integration changes apply everywhere that connection is used. - -Pointer users can drag from the inert widget area; interactive controls are excluded. Containers use the grab button at their top-left corner. -Widgets can be resized from any edge or corner handle. Activate a Container's chrome with its top-left grip before using -its resize handles. -On a touch screen, press and hold a tile for about `200 ms` before moving it; a quick tap does not start a drag. Resize -handles support direct touch input. -Keyboard users can focus a tile, press Enter or Space to start editing, use the arrow keys to move it, and use Shift plus the arrow keys to resize it. -Press Enter, Space, or Escape to stop keyboard editing. -Keyboard moves and resizes apply immediately within the current canvas, rail, or Container; they cannot move an item -between grids. Use pointer drag or **Move / resize item** for that. -Escape stops keyboard editing without undoing those changes. -During a pointer or touch interaction, Escape cancels the move or resize and restores the layout from before that interaction. -Invalid, outside, or otherwise forbidden drops are cancelled in the same way. -The **Move / resize item** action in the edit menu remains available for precise numeric input. - -A focused board tile in keyboard editing mode - -#### Preview - -Layout Settings shows a lightweight structural preview for every layout, including saved spans, Containers, widget labels, and app icons. -It uses a representative viewport width to project the saved geometry; it does not execute widget queries or represent every -pixel of the screen range where the layout is active. - -Choose **Edit layout** to open the real board editor at that representative width on desktop. Save returns to Layout Settings. Cancel discards the local changes. On phones and tablets, the normal board editor continues to use the layout selected by the device width. +Tiles use fixed `200 × 200` logical-pixel cells with a `24px` gap. Homarr scales the complete layout to the available +width instead of changing each widget's proportions. **Reset from Base** regenerates a Mobile or custom layout from the +current Base layout. ### Containers and rails -Containers can hold apps, widgets, and nested Containers. -The same Container model works on the main canvas, inside a fixed rail, or inside another Container. -Move and resize Containers directly in edit mode; nested content stays within the Container's local bounds. -Resize outlines follow the pointer continuously while a dashed preview marks the grid size that will be applied on release. -Each responsive layout stores its own Container position and size. +A **Container** groups apps, widgets, and nested Containers. It can have a label, collapse control, app-opening action, +border color, and CSS classes. -Each Container can configure: +A **rail** reserves one to three columns at the left or right of a non-Mobile layout. Rails stay fixed while the page +scrolls and store their contents separately for each layout. -- Its label and whether that label is visible. -- Whether users can collapse and expand it like an accordion. -- Whether its menu shows **Open all in new tabs** for the app links it contains. -- Its border color and custom CSS classes. +## Edit a board -Collapsing a Container reduces its full-width header to a half-row expansion bar and compacts the surrounding layout without losing its expanded size. -Expanding it smoothly restores those bounds and moves following items out of the way without reloading the widgets inside it. +Enter edit mode from the board header to add, move, resize, configure, or remove content. Save the board to persist the +layout. -### Background +- Drag from an item's inactive content area; Containers use their grip. +- Hold `Ctrl` on Windows/Linux or `Cmd` on macOS to select several items. +- Use **Move / resize item** for another canvas, rail, Container, or exact coordinates. +- Keyboard users can focus a tile, press Enter or Space, then move with arrow keys or resize with Shift + arrow keys. +- Press Escape during a pointer or touch interaction to restore the item to its previous position. -When a background image is set, it always covers at least the full browser window height, even if the board's content is shorter (for example when a Container is collapsed). +The add-content menu can create an app, integration, widget, or Container without leaving the board. -#### Background image URL +## Board settings -Homarr can display a background image behind apps and widgets. -This URL can be used to define what image should be shown. +Board settings cover: -#### Background image attachment +- **General:** page title, browser title, logo, and favicon. +- **Layout:** responsive layouts, breakpoints, columns, and rails. +- **Background:** image, attachment, size, and repeat behavior. +- **Appearance:** colors, opacity, icon color, and item radius. +- **Custom CSS:** styles applied only to the current board. +- **Behaviour:** app status and widget context-menu behavior. -This defines whether the background should move when the user scrolls. +See [Styling](/docs/advanced/styling) for board and global CSS. -#### Background image size +Outside edit mode, widgets may expose an advanced view and a context menu for status, refresh, quick options, settings, +and actions. Available controls depend on the widget and the user's board and integration permissions. -This defines whether the background should cover the entire page (and possibly be cropped) or never be cropped but may not cover the entire page. +## Access control -#### Background image repeat +Public boards are readable without signing in. Private boards require user, group, or global access. -This defines whether the background should be repeated if it cannot cover the entire page. -This option can be useful if you have patterns that can be repeated easily (e.g. patterns): +| Board access | View | Edit content and settings | Access control, rename, delete | +| ------------ | ---- | ------------------------- | ------------------------------ | +| View | Yes | No | No | +| Modify | Yes | Yes | No | +| Full | Yes | Yes | Yes | -![](./img/background-repeat.png) +Inherited access comes from group permissions. Resource-specific access can be granted from the board's access-control +section. -### Appearance +Renaming a board changes its URL without a redirect. Deleting a board is permanent. -#### Primary color +## Home boards -Color that can be chosen freely to give accents to active elements. +A **home board** opens at `/` and `/boards`. Desktop and mobile home boards are separate from the responsive layouts +inside a board. -#### Secondary color +Defaults can be set for a user, group, or the whole server. User settings take priority, followed by matching groups, +the `Everyone` group, and server defaults. Server-wide fallback boards must be public. -Color that can be chosen freely to give accents. - -#### Opacity - -Opacity of the colors. - -#### Icon color - -Change the color of your bookmark / app icons. - - - -#### Item radius - -Change the radius of your items and Containers. - - - -### Custom CSS - -This is the field where you can enter custom CSS. -The styling will only be applied on the respective board page. - -When Assistant is enabled, users with modify permission can also ask it to edit the board's General, Background, -Appearance, Custom CSS, and app-status settings. The assistant reads the current stylesheet first and presents an -editable review form before requesting approval to save the change. It does not edit responsive layouts, access control, -or Danger zone actions. - -[See this guide on how to work with custom CSS](/docs/advanced/styling/). - -### Behaviour - -#### Disable app status - -This will disable the status check for apps. - -#### Work directly from the board - -Widgets expose their routine controls without requiring edit mode: - -- Hold `Shift` while hovering a widget that supports advanced view to expand it in place while the other widgets - remain visible but dimmed. Release `Shift` to close it. Hold `Shift` plus `Ctrl` on Windows/Linux or `Cmd` on macOS to - keep the view open until you close it. On touch devices, open it from the widget menu. Other widgets adapt in place - instead. -- When signed in, outside edit mode, and with **Enable right click on widgets** enabled, right-click a widget to inspect - its live query status, refresh its data, change quick options, open settings, or run supported actions. App tiles do - not use this widget menu, and available controls follow your board and integration permissions. - -The widget context menu follows the **Enable right click on widgets** preference in your user settings. On touch devices, -use the widget menu where your browser exposes it. - -### Access control - -With the access control, you can permit a single user or a group to your board. -The users and groups can have one of these three levels of access: - -| **Permission Level** | View board | Edit mode | Settings | Danger zone (eg. delete) | -| -------------------- | ---------- | --------- | -------- | ------------------------ | -| View board | X | | | | -| Modify board | X | X | X | | -| Full access | X | X | X | X | - -The permission level can only be changed after adding the user / group: - -![](./img/change-user-permission-level.png) - -If the board is private and the user is not added in any of the three tabs, they cannot access the board. -They also do not see the board on the start page nor do they have access to any links for the board. - -Groups that have high permissions (e.g. administrator or all board permissions) will be shown as "inherited". -They are permitted implicitly due to their permissions. - -After editing permissions, the save button below the table must be pressed. -Otherwise, all changes will be discarded. - -### Danger zone - -#### Rename - -Renaming a board will break all existing links to it permanently with no redirect. - -#### Board visibility - -By default, boards will be private. This means only authenticated users that are authorized have access. -Making a board public will expose it to everyone - including unauthenticated users. - -#### Delete - -This will permanently delete the board. -This action is irreversible and cannot be undone. - -## Delete boards - -The deletion of boards is permanent and cannot be undone. -There are two ways to delete a board: - -- Navigate to the settings of your board, open the "Danger zone" section and click on the "delete this board" button. -- Navigate to the list of boards in the management pages, click the three dots and click on "delete permanently". - -Both actions will execute the same deletion process. - -## Duplicate boards - -:::note -Duplicating a board will not copy the users and groups that have access to the board -nor the integrations the user does not have access to. -::: - -Duplicating a board will create a new board with the same settings, all responsive layouts, and independent positions as the original board. -Duplicating a board that contains Custom Widgets also requires an administrator. -You can duplicate a board by clicking on the three dots in the list of boards and selecting "Duplicate board". -The name form expands below that board card and can be cancelled without leaving the list. - -## Setting boards as your home board - -The home board is the dashboard, that will be shown at the root path of Homarr or if no board name was passed in the URL. -All the following paths will lead to the home board: - -- `my-homarr.com` -- `my-homarr.com/boards` - -Your home board will have a special small badge at the top right in the list of boards: - -![](./img/home-board-flag.png) - -### For yourself - -To set the home board yourself, the easiest option is to set it directly in the list of boards: - -![](./img/set-as-home-board-menu.png) - -Alternatively, you can also define it via your user profile: - -1. Click on your user profile at the top right -2. Click on `Your preferences` -3. Change the home board in the `home board` dropdown and click on `Save`. - -### For other users - -1. Navigate to the users: `Management` > `Users` > `Manage` -2. Click on the username of the user that you want to adjust -3. Select the desired home board via the dropdown and click on `Save` \ - ![](./img/set-home-board-other-user.png) - -### For user groups - -1. Navigate to the user groups: `Management` > `Users` > `Groups` > `Manage` -2. Go to tab `Settings` -3. Select the desired home board via the dropdown and click on `Save` \ - ![](./img/set-home-board-user-group.png) - -### For whole server - -You can also set a global home board that will be used for all users that have not set a home board themselves. -It will also be used for anonymous users. - -1. Navigate to the settings: `Management` > `Settings` > `Boards` -2. Select the desired home board via the dropdown and click on `Save` \ - ![](./img/set-home-board-global.png) - -:::note -For the global home board you can only select boards that are public. -::: - -### Mobile home board - -The mobile home board controls which board opens for devices that Homarr detects as mobile from the User-Agent header. -This is separate from a board's **Mobile layout**, which controls the layout selected inside that board. -You can set a mobile home board for yourself in your user preferences, for a user or group through management, or for the -whole server with **Global mobile board** under `Management` > `Settings` > `Boards`. - -For signed-in users, Homarr checks the user's mobile home board, then the user's desktop home board, then the mobile and -desktop defaults for the lowest-position matching group, followed by the mobile and desktop defaults for the `Everyone` -group, and finally the server-wide mobile and desktop defaults. Anonymous visitors use the server-wide mobile default and -then the server-wide desktop default. Server-wide fallback boards must be public. See the -[global board defaults](/docs/management/settings#boards) for the complete precedence and the required public-board rule. +See [Users and groups](../users) and [Server settings](../settings#boards). diff --git a/apps/docs/docs/management/certificates/index.mdx b/apps/docs/docs/management/certificates/index.mdx index 0c2b9853a..46f0a6cc7 100644 --- a/apps/docs/docs/management/certificates/index.mdx +++ b/apps/docs/docs/management/certificates/index.mdx @@ -15,6 +15,8 @@ Below you can see a screenshot of the certificates page. The items show the subject, filename and when it expires. The color of the icon indicates how long it is valid. +![The Trusted certificates management page](../img/certificates.png) + ![](./img/screenshot.png) | Color | Meaning | diff --git a/apps/docs/docs/management/custom-widgets/agent-authoring.mdx b/apps/docs/docs/management/custom-widgets/agent-authoring.mdx index 97b6e5548..64e1b86bd 100644 --- a/apps/docs/docs/management/custom-widgets/agent-authoring.mdx +++ b/apps/docs/docs/management/custom-widgets/agent-authoring.mdx @@ -1,153 +1,45 @@ -# Use agents and skills.sh +# Connect an agent -An external agent can create one widget or a coordinated set with the Homarr MCP server. For a set, it researches a -service once, divides distinct user jobs into useful widgets, and validates every definition independently. +An MCP-connected agent can validate, preview, test, and save Custom Widgets. The API key owner must be a Homarr +administrator. -For example, a request for a Seerr widget can become a coordinated library/request-status widget and an interactive -media-search widget that submits requests, when the service's documented API and the user's permissions support those -flows. - -The MCP API key must belong to a Homarr administrator. Non-administrator keys do not list Custom Widget tools, prompts, -or resources. The same administrator requirement applies to the matching HTTP authoring endpoints. - - - View the Custom Widget Skill on skills.sh - - -Install the Agent Skill from the verified Homarr repository: +Install the official skill: ```sh npx skills add https://github.com/homarr-labs/homarr --skill homarr-custom-widget ``` -The portable skill gives concise authoring guidance. For connected agents, Homarr returns a compact `SKILL.md` and a -reference index. The agent loads only the named schema, runtime, or security reference and component documentation the -current design needs. +The skill routes the agent to the release-matched schema, runtime, security, examples, and component metadata. It keeps +those references separate so the agent loads only what the current widget needs. -The workbench's **Copy AI prompt** action is separate. It creates a self-contained prompt below 12,000 characters for an ordinary ChatGPT or Claude conversation. It includes the lean contract, bindings, recommended components, and two polished examples. It never tells an offline model to call MCP tools. - -The source is in [`.agents/skills/homarr-custom-widget`](https://github.com/homarr-labs/homarr/tree/HEAD/.agents/skills/homarr-custom-widget). `HEAD` follows the repository default branch, so the link is not tied to an unreleased feature branch. Homarr does not provide a ZIP archive. - -After publication, run the installation command once. This action registers installation activity. - -Then, verify the skills.sh page. Request official maker attribution for `homarr-labs` from skills.sh. - -Repository code cannot give this attribution. - -## Get MCP resources +## MCP resources - Prompt: `homarr-custom-widget-author` -- Resources: `homarr://custom-widgets/schema`, `components`, `components/{name}`, `examples/{name}`, `skill`, and - `references/{schema|runtime|security}` -- HTTP: `GET /api/custom-widgets/authoring-prompt`, `schema`, `components`, `skill`, and - `reference-{schema|runtime|security}` +- Skill: `homarr://custom-widgets/skill` +- References: `homarr://custom-widgets/references/{schema|runtime|security}` +- Schema: `homarr://custom-widgets/schema` +- Components: `homarr://custom-widgets/components` and `components/{name}` +- Examples: `homarr://custom-widgets/examples/{name}` -The authoring-prompt tool description contains one sentence. The prompt contains the workflow instructions and resource links. +Equivalent HTTP resources are available under `/api/custom-widgets/` for authenticated administrators. -`GET /api/custom-widgets/skill` and `customWidget_getSkill` return a compact structured skill payload: +## Authoring lifecycle -```ts -{ - name: "homarr-custom-widget"; - version: string; - skillMd: string; - references: Array<{ - name: "schema" | "runtime" | "security"; - tool: "customWidget_getReference"; - toolInput: { name: string }; - resource: string; - httpResource: string; - }>; - skillsShUrl: string; - sourceUrl: string; - installCommand: string; -} -``` +1. Load the skill and only the references needed for the design. +2. Read the external API documentation and build the definition. +3. Validate the JSX, then create a preview from the complete definition. +4. Run every returned query and simulate every relevant action against the current preview revision. +5. Inspect the preview and redacted journal. Revise the existing preview for JSX-only changes. +6. Save from the final tested preview. +7. Configure deployment-specific source URLs and credentials, then preview the saved definition again. -The `homarr://custom-widgets/skill` MCP resource returns only the entrypoint Markdown. Named references remain separate -so clients do not pay for unrelated material. +Use `templateLines` for multiline JSX tool input. A preview must have current evidence for every query and action before +it can be saved. Simulation counts as action evidence without performing the mutation. -The component catalog is a compact index of names, categories, safety levels, shared prop names, policies, and example -IDs. Per-component results contain only component-specific props and a reference to shared prop documentation. Use -`customWidget_getSharedProps` once with only the shared prop names needed across the selected components. This avoids -repeating hundreds of global props in every tool result. The catalog and detailed references are deliberately not -embedded in the skill or clipboard prompt. +If the agent does not have a source URL or credential, it can request a short-lived Homarr configuration URL. An +authenticated administrator completes it in Homarr; the agent receives the status, never the plaintext credential. -These interfaces do not return an archive URL or archive hash. +Agents can also search, inspect, install, and configure existing Workshop widgets instead of regenerating them. -## Create a Custom Widget with MCP - -Independent read-only discovery and reference calls can run together. Validation, preview, evidence, revision, and -persistence calls run alone because each changes the active authoring phase. - -1. Load `customWidget_getSkill`. Use its routing index to fetch only applicable named references with - `customWidget_getReference`. -2. For a new manifest, load the compact `schema` reference once; skip it when repairing a supplied valid v2 draft. - Load the heavyweight live schema only when its extra detail is needed. Prefer `customWidget_findComponents` for a focused release-matched - subset and reserve the full catalog for broad exploration, followed by `customWidget_getComponent` for only relevant - installed components and `customWidget_getExample` when one example matches the interaction pattern. Fetch whatever - named documentation the intended design requires without walking the whole catalog. If shared props are needed, - collect their catalog names and call `customWidget_getSharedProps` once for that set. -3. Read the external API documentation. -4. Build each definition, using `templateLines` for multiline JSX tool input. Call `customWidget_validateTemplate` - while drafting to repair JSX without resending the complete manifest. A valid template with an unknown-prop warning - keeps one concrete `customWidget_getComponent` repair lookup active; otherwise proceed directly to preview. Homarr - Assistant exposes only `templateLines` for validation and revision to prevent duplicate JSX tokens; direct MCP clients - may send exactly one of `template` or `templateLines`. -5. Send the coherent complete definition once to `customWidget_previewCreate`. It performs full validation and creates - the preview session. -6. Run `customWidget_previewQuery` for every query returned by the preview and inspect its actual status and data shape. Assistant conversations retain a bounded response preview so large APIs cannot exhaust the model context. Use - `{}` for load queries; manual queries require exactly the returned primitive `parameterNames`. -7. Test every relevant action returned by the preview in simulation mode. Verify its method, parameters, minimum board - permission, confirmation, and invalidated queries before persistence. -8. Open the returned preview path with browser tools. -9. Inspect the redacted journal. For a JSX-only correction, validate the replacement template, then call - `customWidget_previewReviseTemplate` with the session ID. Direct MCP clients may also pass the returned current revision - for optimistic concurrency. It inherits sources, requests, options, and secrets without resending them, increments the - revision, and returns fresh evidence lists. Use a new - `customWidget_previewCreate` session only when sources, requests, or options change. -10. Retest every returned query and action for the current revision. Earlier evidence remains in the journal but cannot - satisfy persistence. -11. Create the widget from that final tested preview with `customWidget_createFromPreview`. The preview session already carries - the source URLs and encrypted credentials supplied during preview; the create call accepts only its session ID plus an - optional target board and persists that tested preview only after every query and action has current evidence. -12. Open its returned management path, and use a structured question when the user must choose whether to place it on a board. -13. Otherwise, ask the user to configure the saved definition with the ten-minute Homarr source-setup URL. -14. Create a final preview with the saved definition ID so Homarr loads its stored credentials, then test it again. -15. Update the saved definition if the final verification finds a problem. `customWidget_update` also accepts - `templateLines` for multiline JSX without resetting omitted options. -16. Repeat the independent preview and persistence lifecycle for every widget in the requested set. - -Template validation returns focused diagnostics. Preview creation and template revision return session metadata plus -query/action checklists without echoing the definition. Keep the candidate locally and reuse the preview session for -persistence. - -For numeric API enums, prefer a guarded indexed literal label array in JSX over repeating a long ternary chain. The -interpreter validates this pattern independently, and it keeps generated templates and repair calls substantially -smaller while still rendering readable statuses. - -A manual `SubFetch` returns to its trigger immediately when its request ID, parameters, or effective definition -changes. Homarr hides the earlier result and does not fetch the new parameters until the user triggers it again, so -bound search and pagination edits cannot silently relabel stale results. - -Dependent bound controls can reset declaratively: `` -returns to page 1 whenever the scalar search value changes. The reset remains local and does not execute a request. - -After a successful manual query, a result-local `` reruns that -query with unchanged parameters without adding another request definition or raw event handler. - -Each source-configuration URL applies to one definition or preview and one source. It is short-lived, single-use, and -can only be opened and completed by an authenticated Homarr administrator. The administrator confirms the server URL, -network scope, and required credential fields directly in Homarr. The agent receives only request status and never -receives plaintext credentials. Preview-scoped values expire with that preview; definition-scoped values persist. - -Agents can install existing widgets without regenerating them: - -1. Search with `customWidget_workshopSearch`. -2. Inspect and validate a result with `customWidget_workshopGet`. -3. Install it with `customWidget_workshopInstall`. -4. Configure deployment-specific URLs and supplied credentials with `customWidget_sourceConfigure`. -5. If the agent does not have those values, call `customWidget_configurationRequestUser` and wait for completion. -6. Test the installed definition, then use `board_addItem` with kind `customApi` and the returned definition ID. - -Homarr encrypts the plaintext immediately. Homarr does not return the plaintext. +See [MCP](/docs/management/mcp) for client configuration and [requests and security](./requests-and-security) for the +runtime limits. diff --git a/apps/docs/docs/management/custom-widgets/authoring.mdx b/apps/docs/docs/management/custom-widgets/authoring.mdx index 8faebf60c..809371d70 100644 --- a/apps/docs/docs/management/custom-widgets/authoring.mdx +++ b/apps/docs/docs/management/custom-widgets/authoring.mdx @@ -1,74 +1,29 @@ # Create a Custom Widget -import { CanonicalCustomWidgetExample } from "@site/src/components/custom-widget-code"; -import workbenchImage from "./img/workbench.png"; -import workbenchMobileImage from "./img/workbench-mobile.png"; -import workbenchValidationImage from "./img/workbench-validation.png"; +The workbench provides editors for general metadata, API sources, requests, widget options, JSX, and preview data. Raw +JSON is available when direct editing is faster. -The workbench exposes **General**, **API sources**, **Requests**, **Options**, **JSX**, and **Preview** sections. Advanced JSON is -available in the manifest and request/option editors. Code and preview sit side by side on desktop; on smaller screens the -**Configure**/**Preview** switch shows one pane at a time and the section navigation scrolls horizontally. Preview sizes display -as **S/M/L** (Compact/Standard/Wide), and fixtures are **Live**, **Loading**, **Empty**, or **Error**. -For multiline JSX, prefer `templateLines` in agent or MCP input and keep the final tested preview as the source of truth before saving. +## Workflow -Custom Widget workbench with configuration sections and a live preview +1. Configure each API source, network scope, authentication method, and credential. +2. Add named queries and actions. Values can reference widget options or invocation parameters. +3. Define widget options and their defaults. +4. Write JSX using `data`, `status`, `options`, and temporary `inputs`. +5. Run **Test and preview**, inspect the response data and redacted request journal, then save. -Mobile Custom Widget workbench with Configure and Preview switch and horizontally scrollable section navigation +Changing the definition, options, or credentials invalidates the previous preview. Preview actions are simulated unless +**Run actions against the configured API** is enabled for that preview session. -The workbench keeps the configuration and preview together so you can inspect validation diagnostics, the redacted request -journal, fixture data, and preview size before saving. Invalid fields stay marked in the form while the preview explains why it -needs attention. +Widget options support text, textarea, number, switch, select, multi-select, slider, date, time, color, icon, URL, +duration, time zone, and JSON controls. Dynamic choices can come from a load query. -Custom Widget workbench showing a Base URL validation error with Test, preview, and Create actions disabled +See the [safe JSX runtime](./custom-jsx), [component reference](./component-reference), and +[request reference](./requests-and-security) for the authoring contract. -## Manual workflow +## Create with another AI service -1. Configure the default API source, network scope, authentication, and credential. -2. Add query/action cards. Values can be literals, widget options, or invocation parameters. -3. Add widget options with their control and default value. -4. Write responsive JSX using `data`, `status`, `options`, and temporary `inputs`. -5. Test and preview, inspect Data and the redacted request journal, then save. +**Create or fix with any AI** copies a self-contained prompt for an ordinary ChatGPT or Claude conversation. The model +must return one fenced `json` block containing the complete definition. Paste that block into the workbench, add +credentials separately, and validate it against a real preview. -While focus is inside a code editor, use `Ctrl+Z`/`Cmd+Z` to undo and `Ctrl+Shift+Z`/`Cmd+Shift+Z` to redo. The toolbar exposes the same actions. This history is local to that editor; builder-wide undo is not yet available. - -Changing the definition, instance options, or credentials invalidates the previous preview and its live-action session. Run **Test and preview** again before treating the data or result as current. Automatic load queries are queued with up to four running at once so larger previews stay within the request limit. - - - - - -Every option has a default. Supported controls include text, textarea, number, switch, select, multi-select, slider, date, time, color, icon, URL, duration, time zone, and JSON. Dynamic choices use `choicesFrom: { request, itemsPath?, valuePath, labelPath }`; the request must be a load query without invocation parameters, and you cannot provide both static `choices` and `choicesFrom`. - -Preview actions are simulated by default and recorded in the journal without contacting the service. Enable **Run actions against the configured API** only when you intend a real mutation; live actions still require configured confirmation. - -## ChatGPT or Claude - -Open **Create or fix with any AI**, enter the desired widget and optional API documentation URL, then select the copy action beside the accordion title. The single self-contained prompt is below 12,000 characters, starts with your request, includes the lean contract and two polished examples, and never claims that an offline chat has MCP tools. - -The model must return one fenced `json` block containing the complete widget, including the JSX in its `template` -field. Copy that single block and select **Paste**. Homarr fills the visual builders and the JSX editor -without any placeholder replacement or second paste. - -Homarr shows all actionable schema or JSX errors inline. Enter credentials separately. The copied prompt does not include the -latest preview response; use **Preview** > **Data** to inspect it and mention important response fields in your request. The prompt deliberately -recommends a focused Mantine component set, visual hierarchy, responsive layout, theme compatibility, and loading, -empty, failure, and success states. - -Connected agents should use the skills.sh skill and retrieve the live schema and individual component metadata only as needed. +For an MCP-connected agent, use the [Homarr Custom Widget skill](./agent-authoring) instead. diff --git a/apps/docs/docs/management/custom-widgets/img/workbench-mobile.png b/apps/docs/docs/management/custom-widgets/img/workbench-mobile.png deleted file mode 100644 index c23f6369a..000000000 Binary files a/apps/docs/docs/management/custom-widgets/img/workbench-mobile.png and /dev/null differ diff --git a/apps/docs/docs/management/custom-widgets/img/workbench-validation.png b/apps/docs/docs/management/custom-widgets/img/workbench-validation.png deleted file mode 100644 index e4ec4cc31..000000000 Binary files a/apps/docs/docs/management/custom-widgets/img/workbench-validation.png and /dev/null differ diff --git a/apps/docs/docs/management/custom-widgets/img/workbench.png b/apps/docs/docs/management/custom-widgets/img/workbench.png deleted file mode 100644 index 13f111dca..000000000 Binary files a/apps/docs/docs/management/custom-widgets/img/workbench.png and /dev/null differ diff --git a/apps/docs/docs/management/custom-widgets/index.mdx b/apps/docs/docs/management/custom-widgets/index.mdx index b347f31f8..aa8886119 100644 --- a/apps/docs/docs/management/custom-widgets/index.mdx +++ b/apps/docs/docs/management/custom-widgets/index.mdx @@ -4,120 +4,56 @@ sidebar_label: Overview tags: [Custom Widgets, API, JSX, MCP] --- -import { BundledCustomWidgetGallery, CustomWidgetCodeExample } from "@site/src/components/custom-widget-code"; - -export const completeManifest = `{ - "$schema": "homarr-custom-widget-v2", - "name": "Service status", - "sources": { - "default": { "name": "Service API", "baseUrl": "https://status.example.com", "networkScope": "public", "auth": "none" } - }, - "requests": { "status": { "path": "/api/status" } }, - "options": {}, - "template": "{data.status?.label ?? 'Unknown'}" -}`; +import { CustomWidgetFlowDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams"; # Custom Widgets :::warning Experimental feature -This feature is experimental and may change. Share feedback in the +Custom Widgets may change during the v2 release cycle. Share feedback in the [Custom Widgets discussion](https://github.com/homarr-labs/homarr/discussions/categories/custom-widgets). ::: -Custom JSX v2 is Homarr's only Custom Widget format. A definition contains keyed API sources, keyed requests, optional widget options, and one safe JSX template. Credentials are encrypted separately and never exported. +A **Custom Widget** is a validated `homarr-custom-widget-v2` definition containing API sources, queries and actions, +optional settings, and a safe JSX template. -```ts -interface HomarrCustomWidgetV2 { - $schema: "homarr-custom-widget-v2"; - name: string; - description?: string; - iconUrl?: string; - sources: Record; - requests: Record; - options?: Record; - template: string; -} -``` +Homarr executes requests on the server and renders the template in a restricted runtime. Source credentials are +encrypted separately and are not included in exports, prompts, browser data, or Workshop submissions. -### Design with AI + -The **Design with AI** action is available while creating or editing a custom widget. Describe what the widget should show and, -when [Assistant](../assistant) is enabled, send the request directly from the form. The generated prompt includes the -widget schema and current non-secret configuration, but not the latest preview response. It proposes the matching create or -update tool for your approval. +![The Custom Widgets management page](../img/custom-widgets.png) -Use the preview's **Data** tab to inspect the endpoint's real response shape and mention important fields in your request; the -copied prompt does not automatically include the latest preview response. Saved secrets are never added to the prompt. **Copy to -clipboard** remains available when the Assistant is disabled or when you prefer another AI service. +## Manage Custom Widgets - +Administrators can create, import, duplicate, enable, export, publish, and delete definitions under +**Management → Custom Widgets**. Adding or configuring one on a board also requires permission to modify that board. -The browser renders JSX. Homarr's server executes named requests, applies board permissions and network protections, and injects credentials. The browser never receives source credentials. +Once placed, normal board permissions control rendering and requests. Queries can run for anonymous viewers on public +boards; actions require authentication and the permission declared by the request. -## Permissions +## Authoring -Custom Widget management is an administrator-only surface. Only a Homarr administrator can create, import, migrate, -preview, publish, install, configure, or write secrets, including through HTTP authoring resources or MCP. An API key -only lists Custom Widget MCP tools, prompts, and resources when its owner is an administrator. - -Adding or configuring a Custom Widget placement requires both administrator access and permission to modify that -board. Duplicating a board that contains Custom Widgets also requires an administrator. A non-administrator with -board-modify access can move, resize, change presentation settings, or remove an existing placement, but cannot add one, -change its definition, refresh interval, or Custom Widget options. - -Once an administrator has placed a widget, ordinary board permissions apply to rendering and requests. Authorized -non-administrators can use it on private boards, and queries can render for anonymous viewers on public boards. -Mutations remain authenticated and enforce each request's view, modify, or full permission. - -## Authoring paths - -- [Create a Custom Widget](./authoring) visually or with one copied AI prompt. -- [Use the JSX runtime](./custom-jsx) for data, Mantine components, temporary inputs, and diagnostics. -- [Browse the supported component reference](./component-reference). +- [Create a Custom Widget](./authoring) in the workbench or from a copied AI prompt. +- [Use the safe JSX runtime](./custom-jsx) for data bindings, temporary inputs, and components. +- [Browse the component reference](./component-reference). - [Configure requests and security](./requests-and-security). -- [Use MCP and the skills.sh skill](./agent-authoring). -- [Correct problems](./troubleshooting). +- [Connect an agent](./agent-authoring) through MCP and the Homarr skill. +- [Troubleshoot a definition](./troubleshooting). -The workbench provides visual source, request, and option editors, with raw JSON available for advanced use. Invalid -values remain marked and disable preview and saving until corrected. - -Exports, imports, Workshop, and MCP validate the same schema. Homarr also validates community content before -installation. - -Legacy definitions show a **Migration required** badge. Use **Copy migration prompt**, describe the visible layout -without secrets, and import the returned v2 JSON with **Paste migrated widget**. Homarr preserves the v1 definition and -encrypted secret for rollback; credentials never appear in prompts, logs, or exports. +The workbench validates the same schema used by imports, Workshop, HTTP authoring resources, and MCP. Test every query +and simulate relevant actions before saving. Live preview actions are opt-in because they can change the source service. ## Import and Workshop -Administrators can select **Import from Workshop** while adding a board item. Review the complete source and requested -permissions, then confirm deployment-specific URLs and credentials. Private and loopback URLs must be confirmed or -replaced for the current Homarr installation. +Use **Import from Workshop** while adding board content or import a v2 JSON definition directly. Review the source, +requested permissions, API hosts, and actions before installation, then configure deployment-specific URLs and +credentials in Homarr. -Workshop publishes technically valid widgets immediately; users can vote or report them, and Workshop moderators can -delete submissions. Community moderation is separate from Homarr administration and is not a security boundary. Review -the source before installation and replace personal private-network hosts before publishing. +Legacy definitions show **Migration required**. The migration prompt excludes credentials and the old display template; +describe the visible behavior separately, import the returned v2 definition, and verify it before removing the archived +version. -Connected agents can also search and install Workshop widgets. See [agent authoring](./agent-authoring) for the secure -configuration flow; secret values are never returned through MCP. - -## Reliability and rollback - -Multiple Homarr replicas must use the same Redis service so Custom Widget response caches invalidate consistently. - -Before upgrading, back up the database and `SECRET_ENCRYPTION_KEY`. A v1 rollback can read preserved v1 definitions, -but widgets created only in v2 may be unavailable. - -## Bundled examples - -Homarr seeds five disabled examples without credentials and never overwrites an edited seed. They use the same public -contract. Tautulli Activity is one of the bundled examples preserved from Homarr's AI authoring evaluation: - - +Back up the database and `SECRET_ENCRYPTION_KEY` before upgrading or rolling back. Multi-replica installations must use +the same Redis service so cached responses invalidate consistently. diff --git a/apps/docs/docs/management/custom-widgets/troubleshooting.mdx b/apps/docs/docs/management/custom-widgets/troubleshooting.mdx index 82045509c..07bd0c2fc 100644 --- a/apps/docs/docs/management/custom-widgets/troubleshooting.mdx +++ b/apps/docs/docs/management/custom-widgets/troubleshooting.mdx @@ -1,84 +1,52 @@ -# Correct Custom Widget problems +# Custom Widget troubleshooting -## Correct an unavailable widget +## Definition problems -The definition does not exist. If it was deleted, remove the unavailable tile from the board. +| Symptom | Resolution | +| ------------------------ | ---------------------------------------------------------------------------------------------------------- | +| Definition unavailable | Restore or recreate the definition, or remove the unavailable board item. | +| **Migration required** | Copy the migration prompt, describe the visible behavior without secrets, and import the returned v2 JSON. | +| Invalid saved definition | Read the displayed schema errors, then recreate or import a valid definition. | +| Invalid item options | Open the board item's settings and correct values that no longer match the definition. | -If the Custom Widgets page shows the definition with a **Migration required** badge, an administrator can open its -action menu and select **Copy migration prompt**. Give that redacted prompt to an LLM, then import the resulting v2 JSON -from the same menu. The LLM returns one complete JSON block; copy it once and select **Paste migrated widget**. Homarr -places its `template` value into the JSX editor automatically. Because arbitrary v1 display text or JSX may contain -credentials, the prompt omits that display configuration; describe the old widget's visible layout and behavior without -including secrets. Other viewers see **Contact an administrator** instead of a migration link. +Migrating a v1 definition keeps the archived v1 record and encrypted secret for rollback. The migrated v2 definition +uses the same ID and takes precedence. -Homarr keeps the v1 definition and encrypted secret after migration. The validated v2 replacement uses the same ID and -takes precedence; the archived v1 record reappears if the v2 replacement is deleted. There is no v1 permanent-delete -action during the v2 stabilization period. +## Validation errors -Otherwise, install or create a Custom JSX v2 definition. +Start with the first diagnostic and its field path. Common causes are: -## Correct an invalid saved definition +- invalid or duplicate source, request, or option IDs; +- a request referencing a missing source; +- an option default that does not match its control; +- `{param:name}` in a load query; +- missing invocation parameters; +- an invalid source or icon URL; +- a runtime component using the wrong request kind. -The Custom Widgets page isolates a definition that does not conform to the current schema. The other definitions remain available. +The Diagnostics tab also shows JSX errors, accessibility checks, and the redacted request journal. -An invalid definition shows its validation errors. You can delete it. +## Request errors -You cannot edit, enable, export, duplicate, publish, or select an invalid v2 definition. Recreate the definition or import a valid definition. Preserved v1 definitions use the separate **Migration required** workflow described above. +Check the source URL, network scope, authentication, request method, path, body bindings, and board permission. The +journal records the request ID, method, path template, status, and duration without credentials. -## Correct validation errors +For `invalid placeholder`, use `{option:name}` or `{param:name}`. Load queries can reference options only. -Read the first schema or JSX diagnostic. Use its path to find the invalid value. +In multi-replica deployments, connect every Homarr replica to the same Redis database. Otherwise an action can leave a +stale cached query on another replica. -Make sure keyed API source and request names are valid and unique. +## Runtime warnings -Make sure that each named request references an API source. Use explicit `$option` and `$param` references. - -Make sure every option default matches its control. Use the correct request kind for each runtime component. - -An incomplete API source URL or icon URL causes a form validation error. The workbench keeps the draft open. - -The workbench marks the invalid field while you type. An invalid URL does not replace the form with the error boundary. - -An invalid definition disables widget preview and Save/Create. The Data, Options, Actions, and Diagnostics tabs remain available so you can correct it. - -The Diagnostics tab shows current schema and JSX errors, accessibility checks, and (after a preview) the redacted request -journal. It does not expose credentials or raw secret values. +`UNKNOWN_MANTINE_PROP` means the installed Mantine component does not document that property. Check the +[component reference](./component-reference). `BLOCKED_CAPABILITY` means the runtime rejected an unsafe component, +property, URL, or style capability. ## Workshop unavailable -If Workshop is unavailable, check `WORKSHOP_API_URL` and PocketBase health. Widgets that are already installed continue -to work. +Check `WORKSHOP_API_URL` and PocketBase health. Installed widgets continue to run without Workshop. -## Correct request errors +## Rollback -Check the API source network scope. Check the base URL and credentials. - -Check the request method, path, body, direct value bindings, and board permission. - -For “invalid placeholder,” use `{option:name}` or `{param:name}`. Load queries can only reference options. The preview journal does not show credentials. - -The journal shows the method, request ID, path template, status, and duration. - -In a multi-instance deployment, all Homarr replicas must share Redis. Versioned cache invalidation is distributed -through Redis; replicas connected to different Redis databases can serve stale query responses after an action. - -## Correct a Mantine prop warning - -`UNKNOWN_MANTINE_PROP` is a warning. Homarr passes the prop to Mantine. - -Check the prop in the documentation for the installed Mantine version. `BLOCKED_CAPABILITY` identifies an unsafe capability. - -Use safe widget options, temporary inputs, or named requests instead. - -## Repair an existing item - -The widget option definitions changed and the saved values are invalid. Open the item settings. - -Correct the marked configuration values. Homarr does not infer widget option migrations. - -## Roll back safely - -Before an application upgrade, back up the database and preserve the exact `SECRET_ENCRYPTION_KEY`. The v2 schema keeps -the physical v1 definition and secret tables readable by a v1 binary. Roll back the application without running -manual cleanup, verify legacy widgets, and restore the database backup if the migration itself must be reversed. -PocketBase Workshop data is a separate backup and restore operation. +Preserve a database backup and the exact `SECRET_ENCRYPTION_KEY`. Roll back the Homarr application without manually +removing the v1 tables. Workshop's PocketBase data has a separate backup lifecycle. diff --git a/apps/docs/docs/management/img/api.png b/apps/docs/docs/management/img/api.png new file mode 100644 index 000000000..794c0d8ea Binary files /dev/null and b/apps/docs/docs/management/img/api.png differ diff --git a/apps/docs/docs/management/img/apps.png b/apps/docs/docs/management/img/apps.png new file mode 100644 index 000000000..96270fe56 Binary files /dev/null and b/apps/docs/docs/management/img/apps.png differ diff --git a/apps/docs/docs/management/img/assistant-config.png b/apps/docs/docs/management/img/assistant-config.png deleted file mode 100644 index 181d297b0..000000000 Binary files a/apps/docs/docs/management/img/assistant-config.png and /dev/null differ diff --git a/apps/docs/docs/management/img/assistant-widget.png b/apps/docs/docs/management/img/assistant-widget.png deleted file mode 100644 index 960d9ab40..000000000 Binary files a/apps/docs/docs/management/img/assistant-widget.png and /dev/null differ diff --git a/apps/docs/docs/management/img/assistant.png b/apps/docs/docs/management/img/assistant.png new file mode 100644 index 000000000..9bbd64d95 Binary files /dev/null and b/apps/docs/docs/management/img/assistant.png differ diff --git a/apps/docs/docs/management/img/backup.png b/apps/docs/docs/management/img/backup.png new file mode 100644 index 000000000..2408f3095 Binary files /dev/null and b/apps/docs/docs/management/img/backup.png differ diff --git a/apps/docs/docs/management/img/boards.png b/apps/docs/docs/management/img/boards.png new file mode 100644 index 000000000..0a83d3eda Binary files /dev/null and b/apps/docs/docs/management/img/boards.png differ diff --git a/apps/docs/docs/management/img/certificates.png b/apps/docs/docs/management/img/certificates.png new file mode 100644 index 000000000..68cd7cab1 Binary files /dev/null and b/apps/docs/docs/management/img/certificates.png differ diff --git a/apps/docs/docs/management/img/custom-widgets.png b/apps/docs/docs/management/img/custom-widgets.png new file mode 100644 index 000000000..92e7a7fd9 Binary files /dev/null and b/apps/docs/docs/management/img/custom-widgets.png differ diff --git a/apps/docs/docs/management/img/integrations-catalog.png b/apps/docs/docs/management/img/integrations-catalog.png new file mode 100644 index 000000000..460f125aa Binary files /dev/null and b/apps/docs/docs/management/img/integrations-catalog.png differ diff --git a/apps/docs/docs/management/img/logs.png b/apps/docs/docs/management/img/logs.png new file mode 100644 index 000000000..9eba3a1f1 Binary files /dev/null and b/apps/docs/docs/management/img/logs.png differ diff --git a/apps/docs/docs/management/img/mcp.png b/apps/docs/docs/management/img/mcp.png new file mode 100644 index 000000000..689a44fb3 Binary files /dev/null and b/apps/docs/docs/management/img/mcp.png differ diff --git a/apps/docs/docs/management/img/media.png b/apps/docs/docs/management/img/media.png new file mode 100644 index 000000000..a5f0f1420 Binary files /dev/null and b/apps/docs/docs/management/img/media.png differ diff --git a/apps/docs/docs/management/img/search-engines.png b/apps/docs/docs/management/img/search-engines.png new file mode 100644 index 000000000..0c7172f08 Binary files /dev/null and b/apps/docs/docs/management/img/search-engines.png differ diff --git a/apps/docs/docs/management/img/settings-overview.png b/apps/docs/docs/management/img/settings-overview.png new file mode 100644 index 000000000..bf4cc5936 Binary files /dev/null and b/apps/docs/docs/management/img/settings-overview.png differ diff --git a/apps/docs/docs/management/img/tasks.png b/apps/docs/docs/management/img/tasks.png new file mode 100644 index 000000000..7f03adf18 Binary files /dev/null and b/apps/docs/docs/management/img/tasks.png differ diff --git a/apps/docs/docs/management/img/users-groups.png b/apps/docs/docs/management/img/users-groups.png new file mode 100644 index 000000000..4da9825c6 Binary files /dev/null and b/apps/docs/docs/management/img/users-groups.png differ diff --git a/apps/docs/docs/management/img/users.png b/apps/docs/docs/management/img/users.png new file mode 100644 index 000000000..2848cb22a Binary files /dev/null and b/apps/docs/docs/management/img/users.png differ diff --git a/apps/docs/docs/management/integrations/index.mdx b/apps/docs/docs/management/integrations/index.mdx index ab566a1a3..2bb019883 100644 --- a/apps/docs/docs/management/integrations/index.mdx +++ b/apps/docs/docs/management/integrations/index.mdx @@ -5,137 +5,58 @@ tags: - Connections --- +import { IntegrationRoutesDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams"; + # Integrations -Integrations are connections to supported third party applications. -This page will describe the process of managing integrations but the process may vary depending on your specific integration. -Check [the available integrations](/docs/category/integrations) for further information. +An **integration** is a server-side connection from Homarr to a supported service. Integrations provide data and +actions to widgets and can be linked to apps. -## Create an integration +![The integration catalog](../img/integrations-catalog.png) -To create an integration, choose **New integration** and select the supported application from the searchable grid. The grid groups related services visually and shows which widgets each integration supports. +See the [integration catalog](/docs/category/integrations) for service-specific URLs, credentials, and supported +widgets. -The integrations management page uses a searchable list. Each row shows the integration type and URL, with the actions you have permission to use. +## Browser and server routes -### Accessing the page + -The `/manage/integrations` page is reachable when at least one of the following applies: +## Configuration -- you can manage all integrations (global `integration-full-all`), -- you can create integrations (`integration-create`), or -- you have been granted full access to at least one specific integration. +Create and manage integrations under **Management → Integrations**. Select a service, provide its base URL and required +credentials, then test the connection. Homarr does not save a new integration until the test succeeds. -What the page shows depends on the case: +Use a URL reachable from the Homarr server or container. Unless an integration page says otherwise, provide the service +root rather than a settings or API subpage. -- **Manage all (`integration-full-all`)**: the full list of integrations is shown. -- **Create only (`integration-create`)**: the page shows an empty "create an integration" state instead of the list, with the create action still available. -- **Delegated (full access on one or more)**: only the integrations you have full access to are listed, above a note making clear that the view is scoped to what you can manage. -- **None**: the page is not reachable and returns a not-found page. +Credentials are encrypted and used only by the server. Linking an app is optional; it provides the browser-facing URL +used by widgets that open the service. -Where you have a mix of access, the list combines the integrations you can manage. Integration lists are filtered -server side, so a user never receives data about integrations they lack access to. +![Creating an integration with a server URL, API key, and linked app](./img/form-create-integration.png) -Next, you'll need to fill out the required fields to configure the integration: +Integrations can also be created while adding content to a board. Editing a connection from a widget updates that +integration everywhere it is used. -![](./img/form-create-integration.png) +## Permissions -### Name +| Level | Allows | +| -------- | -------------------------------------------------------- | +| Use | Select the integration and read its data | +| Interact | Run supported actions, such as pausing a download | +| Full | Change the URL, credentials, permissions, and linked app | -Must be at least 1 character long, can be chosen freely. +![Per-integration access for users and groups](./img/integration-permissions.png) -### Url +Global integration permissions apply to every integration. Resource access can instead be granted to specific users +or groups. Lists are filtered on the server and only include connections the current user can manage. -This must be the base URL of the application where Homarr should connect to. -A few examples for this field include: +## Connection problems -- http://sabnzbd.example.com -- https://example.com/sabnzbd +If a connection test fails: -You must not append any path after the base URL. Some examples for incorrect usage: +1. Check the integration page for the required base URL and credentials. +2. Test name resolution and HTTP access from the Homarr container or pod, not only from the host or browser. +3. Check Homarr and upstream-service logs, then any reverse proxy, firewall, VLAN, VPN, or DNS between them. +4. For a self-signed certificate, add the expected certificate under [Certificates](../certificates). -- http://sabnzbd.example.com/settings -- https://example.com/sabnzbd/settings - -### Secrets - -An integration may or may not require secrets to function. -To process to obtain them is usually [documented in the integration pages](/docs/category/integrations). -Secrets are encrypted using a symmetric encryption and stored in the database. -To improve security, they will never be passed to the client and requests to the integrations are performed from the host where Homarr is running on. - -### Linking applications - -During the creation of an integration you can choose to add / link an application to the integration. -If you want to add one, you can simply specify the app url which will be used for opening the application from Homarr. -The linked application will also be used for any links the integration widget contains. -If you already have an application created, you can also link it to the integration by selecting it from the dropdown. -On the edit page you can always change or remove the linked application. - -### Testing and saving integration - -It is not allowed to create an integration without passing the test. -This is to ensure that you minimize the amount of broken applications on your Homarr instance. -The test and create button will perform a network request to the application and authenticate if required. - -When you connect a service from a board, Homarr keeps you in the same setup flow. After the connection succeeds, it -confirms whether an application shortcut was linked and offers the widgets that support the new integration. Selecting a -widget returns to its settings with the new integration already selected. - -Users with full access can also test and update a selected integration directly in the **Edit widget → Edit integration** -tab on a board. Failed tests keep the editor open and show the same connection diagnostics as the management page. -Successful changes apply to every app and widget that uses the integration. - -When app creation is not permitted, the setup form offers linking an existing accessible app instead of attempting to -create one. - -When the connection unlocks useful widgets that are not on the current board yet, the confirmation also shows up to -three explainable recommendations. A recommendation is based only on the services you can use and the widget kinds -already present on that board. You can open the existing widget picker prefiltered to the recommendation, or dismiss -recommendations for that service on that board. - -## Managing permissions - -On the edit page of an integration, you can manage which users / groups can - -- **Select the integration in items:** Allows users to select the integration and showing data on their board. -- **Interact with the integration:** Allows users to perform actions on the integration, such as pausing a download. -- **Full control over the integration:** Allows users to modify the integration properties, including the URL and secrets. - -![](./img/integration-permissions.png) - -## Troubleshooting connection - -The connection to your integrations can fail due to many factors. Most of the time it should show you the reason why it failed. -If it doesn't, you can follow these steps to troubleshoot the issue: - -1. Check whether you are using the correct URL and secrets. - - The URL must be the base URL of the application, **without any paths**. - - The secrets must be correct and have the correct permissions. -2. If you use https to connect to the application, check the chapter below about [certificate issues](#certificate-issues). -3. Check whether you followed the Homarr documentation and didn't skip any steps. - This is the most often mistake that create many noisy support requests and following all steps will often resolve the problems. -4. Check Homarr's logs for more information. As we have no control over breaking changes in upstream APIs and third party software, - they can break without notice in unexpected ways which can also lead to errors within Homarr. In such case, these occurrences must be reported - and fixed within the source code of Homarr. -5. Check whether the host can reach the destination hostname / IP using `ping` and `curl` or `wget` afterward. - Execute this command on the host machine, not inside containers, to check whether it can connect or not. -6. Check whether the container / pod can reach the destination hostname / IP. Execute the same commands in the shell inside the container / pod. -7. Check your reverse proxy / authentication proxy logs for failures / hints -8. Check your security log of tunnels and VPNs -9. Check your router for security events -10. Check your VLAN configuration and firewall rules -11. Check your DNS settings for the host machine and the containers / pods and whether they can resolve the hostnames -12. Check throughput and stability of your network connection using `iperf3` -13. Check syslog / drivers of your OS for hints -14. Check logs of your destination applications (eg. SABnzbd) -15. Attempt to disable CSRF / tamper protections when absolutely no other workaround available -> this comes with some security implications - be careful! - Re-enable if this didn't fix the issue. - -If none of these troubleshooting steps worked, you can request support from our team in Discord or GitHub. - -### Certificate issues - -If you are using a self-signed certificate you'll need to add it to the [trusted certificates](../certificates) in Homarr. -Most of the time you should also get a button to add the certificate automatically when you try to connect to the integration. -Please check that the certificate is the one you are expecting to prevent Man in the Middle attacks. -For some integrations, you can find a guide on how to retrieve the certificate [here](../certificates/#obtaining-certificates). +Do not disable upstream security controls as a general troubleshooting step. diff --git a/apps/docs/docs/management/logs/index.mdx b/apps/docs/docs/management/logs/index.mdx index 1bf22f7a9..b1b121a4c 100644 --- a/apps/docs/docs/management/logs/index.mdx +++ b/apps/docs/docs/management/logs/index.mdx @@ -10,6 +10,8 @@ tags: The logs page shows recent Homarr application logs and continues updating as new events occur. Use it to investigate widget, integration, and server errors without opening the container logs separately. +![The live Logs management page](../img/logs.png) + ## Opening the logs page Navigate to **Management** > **Tools** > **Logs**. The page and widget log links are only available to users with the diff --git a/apps/docs/docs/management/mcp.mdx b/apps/docs/docs/management/mcp.mdx index 2b0de0f5e..79c999c68 100644 --- a/apps/docs/docs/management/mcp.mdx +++ b/apps/docs/docs/management/mcp.mdx @@ -8,285 +8,81 @@ tags: # Model Context Protocol (MCP) -Homarr exposes a [Model Context Protocol](https://modelcontextprotocol.io) server at `/api/mcp`, enabling AI assistants like Claude, Cursor, VS Code Copilot, and Claude Code to interact with your Homarr instance using natural language. +Homarr exposes a stateless [Model Context Protocol](https://modelcontextprotocol.io) server at `/api/mcp`. It maps the +current Homarr API to tools for compatible AI clients. -The endpoint implements the stateless MCP 2026-07-28 protocol and accepts 2025 Streamable HTTP clients through a -stateless compatibility path. It does not create protocol sessions or require sticky sessions. Homarr creates the -server and extracts its tools only after an authenticated request reaches the route. The previous `/api/mcp/mcp` URL -remains available as a compatibility alias, but new clients should always use `/api/mcp`. +![The AI / MCP management tab](./img/mcp.png) -With MCP, you can ask your AI assistant to manage apps, integrations, users, boards, Docker and Kubernetes resources, -media servers, DNS settings, and more through Homarr's existing tRPC API. +The endpoint implements MCP `2026-07-28` and accepts 2025 Streamable HTTP clients through a compatibility path. The old +`/api/mcp/mcp` route remains as an alias; use `/api/mcp` for new clients. -The optional [Assistant](./assistant) uses this same complete tool catalog internally, but sends only a relevant subset -of schemas to the model at each step. It uses the current Homarr session directly and asks for in-conversation approval -before running mutating procedures. +## Configure a client -## Getting Started - -The MCP endpoint lives under the **API** page at `Management` → `Tools` → `API` → **AI / MCP** tab. - -![AI / MCP tab showing the endpoint, API-key warning, and client configuration](./api/img/mcp-instructions.png) - -### 1. Create an API Key - -Navigate to the **Authentication** tab in the API page and create an API key. API keys follow the format `.`. -You can also create one directly from the MCP tab if you don't have any keys yet. - -### 2. Choose a Transport - -| Transport | Best For | Requirements | -| ------------------- | ------------------------------------------------------------ | ------------------------------ | -| **Streamable HTTP** | Cursor, Claude Desktop, VS Code Copilot, Claude Code | Direct HTTP access to Homarr | -| **STDIO** | Firewall-restricted environments, offline-compatible clients | `npx` and `mcp-remote` package | - -**Streamable HTTP** is recommended for most setups. It works with all major AI clients. - -### 3. Configure Your Client - -Add the following to your client's MCP configuration file: - -**Streamable HTTP** (recommended): +Create an API key under **Management → Tools → API → Authentication**, then add the endpoint and header to the client's +MCP configuration: ```json { "mcpServers": { "homarr": { - "url": "https://your-homarr-instance.com/api/mcp", + "url": "https://homarr.example.com/api/mcp", "headers": { - "ApiKey": "" + "ApiKey": "." } } } } ``` -Where to place this config: - -| Client | Config File | -| --------------- | ----------------------------------------------- | -| Cursor | `.cursor/mcp.json` | -| Claude Desktop | `claude_desktop_config.json` | -| Claude Code | `.claude/mcp.json` (or `claude mcp add homarr`) | -| VS Code Copilot | `.vscode/mcp.json` | - -:::warning - -Replace `` with your actual API key. Never commit API keys to version control. - -::: - -**STDIO** (alternative): +Clients without Streamable HTTP support can use `mcp-remote` over STDIO: ```json { "mcpServers": { "homarr": { "command": "npx", - "args": ["-y", "mcp-remote", "https://your-homarr-instance.com/api/mcp", "--header", "ApiKey:"] + "args": ["-y", "mcp-remote", "https://homarr.example.com/api/mcp", "--header", "ApiKey:."] } } } ``` -This option tunnels MCP communication through STDIO using the `mcp-remote` package. Useful when the AI client cannot make HTTP requests directly. +The **AI / MCP** tab on Homarr's API page shows the current endpoint, configuration, and generated tool catalog. -## Authentication +## Authentication and permissions -MCP supports two authentication methods: +MCP supports API keys and OAuth 2.1 with PKCE. API keys are simpler for direct client configuration; OAuth is available +for clients that support dynamic authorization. -| Method | Description | Best For | -| -------------------- | ----------------------------------------------------- | ---------------------------------------------------------------- | -| **API Key** | Include `ApiKey: .` header in all requests | Scripts, CI/CD, direct client configs | -| **OAuth 2.1 + PKCE** | Full OAuth flow with dynamic client registration | MCP clients with OAuth support (e.g. `opencode mcp auth homarr`) | +Tools use the permissions of the API key owner or authorized user. Creating a key does not grant additional access. +Custom Widget and Workshop authoring tools, prompts, and resources are visible only to administrators. -API key authentication is simpler and recommended for most setups. The API key inherits the permissions of the user who created it. Tools that require higher privileges will return permission errors if the key lacks access. +Use HTTPS when the endpoint crosses an untrusted network. -Custom Widget and Workshop authoring are different: their tools, prompts, and resources are exposed only when the API -key owner is a Homarr administrator. Non-administrator keys cannot discover or invoke those capabilities. Creating an -API key never elevates the owner. +## Verify the endpoint -OAuth authorization and token requests bind issued credentials to the canonical `/api/mcp` resource. Dynamic client -registration remains available for compatibility with current MCP clients while the ecosystem transitions toward -pre-registered clients and Client ID Metadata Documents. +The 2025 compatibility path accepts a compact `tools/list` request: -## Testing the Connection - -Verify your MCP endpoint is working: - -```bash -curl -s -X POST \ - -H "Content-Type: application/json" \ - -H "Accept: application/json" \ - -H "ApiKey: " \ - -H "Mcp-Method: server/discover" \ - -H "Mcp-Name: homarr" \ - -d '{"jsonrpc":"2.0","method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"test","version":"1.0"},"io.modelcontextprotocol/clientCapabilities":{}}},"id":1}' \ - https://your-homarr-instance.com/api/mcp -``` - -A successful response includes the supported protocol versions and server capabilities. Use `tools/list` to see all -available tools. MCP v2 clients add the per-request metadata and `Mcp-Method` / `Mcp-Name` headers automatically; the -abbreviated request below uses the stateless 2025 compatibility path for readability: - -```bash -curl -s -X POST \ - -H "Content-Type: application/json" \ - -H "Accept: application/json, text/event-stream" \ - -H "ApiKey: " \ +```sh +curl -X POST \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json, text/event-stream' \ + -H 'ApiKey: .' \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' \ - https://your-homarr-instance.com/api/mcp + https://homarr.example.com/api/mcp ``` -Tool catalogs are returned in deterministic order and may be cached privately by the client for five minutes. The -removed HTTP+SSE `/sse` and `/message` transports return `410 Gone`; use the single Streamable HTTP endpoint instead. +The removed HTTP+SSE `/sse` and `/message` transports return `410 Gone`. -## Available Tools +## Tools and resources -Homarr exposes 50+ tools organized by namespace. Each tool is either a **query** (GET, read-only) or **mutation** (POST, write action). +The generated catalog includes available board, app, integration, Docker, Kubernetes, media, DNS, download, and other +Homarr procedures. Queries are read-only; mutations change state. The exact catalog depends on the release and current +user permissions, so inspect `tools/list` or the table in Homarr instead of relying on a static list. -| Namespace | Example Tools | Type | -| ------------------ | ---------------------------------------------------------- | ---------- | -| `app` | List all apps, get app by ID, create/update/delete app | GET + POST | -| `apiKeys` | List API keys | GET | -| `beszel` | Systems status, alerts, historical system metrics | GET | -| `board` | List boards, read settings/CSS, create/update/delete board | GET + POST | -| `docker` | List containers, inspect container, start/stop/restart | GET + POST | -| `icon` | Search icons | GET | -| `info` | Server health, version info | GET | -| `integration` | List integrations, test connection, delete integration | GET + POST | -| `invite` | List invitations, delete invite | GET + POST | -| `calendar` | Calendar events from media servers | GET | -| `customWidget` | Validate, preview, create, and iteratively update widgets | GET + POST | -| `dnsHole` | DNS hole summary, toggle blocking | GET + POST | -| `downloads` | Active downloads, pause/resume/delete | GET + POST | -| `healthMonitoring` | Resource usage stats | GET | -| `patchmon` | Host patch and security update statistics | GET | -| `mediaRequests` | Approve/decline media requests | GET + POST | -| `mediaServer` | Media server sessions and stats | GET | -| `smartHome` | Execute automations, device states | GET + POST | +For Custom Widgets, install the official skill and follow the preview-and-evidence workflow described in +[Connect an agent](./custom-widgets/agent-authoring). Secret values are configured in Homarr and are never returned +through MCP. -The tools table on the MCP tab is dynamically generated - it always reflects the latest available procedures from your Homarr instance. - -## Security - -- API keys are required for authentication - unauthenticated requests are rejected -- Tools inherit the permissions of the API key's owner -- OAuth endpoints are rate-limited to prevent abuse -- Tool execution errors are contained - a failing tool call does not crash the MCP server -- Custom-widget MCP actions are simulation-only; live preview actions must be enabled explicitly in the browser workbench -- Custom-widget secret values are never returned through MCP -- All communication uses HTTPS (configure HTTP → HTTPS redirects on your reverse proxy) - -## Use Cases - -- **"Show me all apps on my Homarr dashboard"** - AI lists all apps with their names and URLs -- **"Restart the Plex Docker container"** - AI finds and restarts the container via Docker integration -- **"What's downloading right now?"** - AI fetches active download status across all download integrations -- **"Create a new app pointing to my Grafana instance"** - AI creates an app with the correct icon and URL -- **"How many users are on my Homarr instance?"** - AI lists all users (admin only) -- **"Toggle Pi-hole blocking for 5 minutes"** - AI interacts with DNS controls -- **"How are my servers doing?"** - AI fetches Beszel system stats including CPU, memory, disk, and alerts -- **"Build two Custom Widgets for this API"** - AI researches once, then validates and previews each definition before saving it - -## Create a Custom Widget with an AI agent - -An agent can create one `homarr-custom-widget-v2` definition or a coordinated set. Start with the native prompt -`homarr-custom-widget-author`. - -The API key owner must be a Homarr administrator. The same rule applies to management, import, migration, preview, -secrets, publication, Workshop installation, and the HTTP authoring resources. - -Load the installed skill before authoring. `customWidget_getSkill` returns its compact `SKILL.md` entrypoint and a -reference index. Load a named schema, runtime, or security reference with `customWidget_getReference` only when the -design needs it. Read the live JSON Schema or component resources when their detail is required by the design. - -1. Call `customWidget_getSkill`. Homarr Assistant stages the next typed authoring tools automatically as the widget - moves through context, validation, preview, evidence, and persistence phases. -2. Load the live schema and applicable named references on demand. Prefer `customWidget_findComponents` for a small - release-matched result set; reserve the full catalog for broad exploration. Fetch only relevant installed component - documentation with `customWidget_getComponents` (or `customWidget_getComponent` for one repair) and, when useful, - one interaction example with `customWidget_getExample`. Component results contain component-specific props; collect - any needed shared prop names from the compact catalog and fetch them together once with `customWidget_getSharedProps`. -3. Build each Custom Widget definition. Use `templateLines` for generated multiline JSX and - `customWidget_validateTemplate` for focused JSX diagnostics without resending the complete manifest. -4. Send the coherent complete definition once to `customWidget_previewCreate`; preview creation performs full - validation and creates the testable preview. -5. Call `customWidget_previewQuery` for every entry in the returned `queries` list. Supply the listed invocation - parameters for manual queries and inspect the real HTTP status and response shape before binding template fields. -6. Test every relevant entry in the returned `actions` list with `customWidget_previewAction` in simulation mode. The - list exposes each action's method, parameters, minimum board permission, confirmation, and invalidated queries. -7. Open the returned `previewPath` or `previewUrl`. -8. Examine `customWidget_previewJournal`. -9. For a JSX-only evidence correction, validate it and call `customWidget_previewReviseTemplate` with the session ID - and revision. It inherits the manifest and returns fresh evidence lists without resending sources, requests, or - options. Create another preview only when those manifest sections change. -10. Retest every returned query and action for the current revision, then call `customWidget_createFromPreview` with - the session ID so the definition is not streamed again. -11. Open the returned `managementPath` to review the exact saved definition. -12. If the user must enter the source URL or credentials, call `customWidget_configurationRequestUser` with the new definition ID and wait for completion. -13. Create a final preview with that definition ID so Homarr loads its stored credentials, then test it again. -14. Use `customWidget_update` or `customWidget_templatePatch` for any final saved-definition corrections. -15. Repeat the independent preview and persistence lifecycle for every definition in the requested set. - -Validation, preview creation, and template revision return compact lifecycle metadata. They do not echo the submitted -widget or duplicate its template as both a string and line array; the agent should retain and reuse its local candidate. - -The agent receives the configuration-request status. The agent does not receive plaintext credentials. A preview-scoped setup URL configures only that temporary preview; use a definition-scoped URL when the values must persist. - -Discovery resources: - -- `homarr://custom-widgets/schema` -- `homarr://custom-widgets/components` -- `homarr://custom-widgets/components/{name}` -- `homarr://custom-widgets/examples/{name}` -- `homarr://custom-widgets/skill` -- `homarr://custom-widgets/references/{schema|runtime|security}` - -An authenticated administrator can use the matching `/api/custom-widgets/authoring-prompt`, `/schema`, `/components`, -and `/skill` endpoints instead of MCP resource URIs. These endpoints are not public schema downloads. - -The Custom Widget tools are: - -- `customWidget_schema` -- `customWidget_validate` -- `customWidget_validateTemplate` -- `customWidget_list` -- `customWidget_get` -- `customWidget_create` -- `customWidget_createFromPreview` -- `customWidget_update` -- `customWidget_delete` -- `customWidget_templatePatch` -- `customWidget_previewCreate` -- `customWidget_previewReviseTemplate` -- `customWidget_previewQuery` -- `customWidget_previewAction` -- `customWidget_previewJournal` -- `customWidget_secretSet` -- `customWidget_sourceConfigure` -- `customWidget_configurationRequestUser` -- `customWidget_workshopSearch` -- `customWidget_workshopGet` -- `customWidget_workshopInstall` -- `customWidget_getAuthoringPrompt` -- `customWidget_getComponentCatalog` -- `customWidget_findComponents` -- `customWidget_getComponents` -- `customWidget_getComponent` -- `customWidget_getSharedProps` -- `customWidget_getExample` -- `customWidget_getSkill` -- `customWidget_getReference` - -Custom Widget permissions are not assignable group capabilities. Administrator status is required for the complete -authoring surface. A source-configuration URL is short-lived and single-use, requires the same logged-in administrator -to open and complete it, and never returns plaintext credentials to the agent. - -Adding a `customApi` item through `board_addItem`, changing its definition or options, and duplicating a board that -contains one also require an administrator with board-modify access. Existing placements continue to render and run -authorized requests according to normal board permissions. - -Homarr applies its request security controls during request execution. These controls include SSRF, DNS, redirect, size, timeout, rate, and permission controls. - -Read [Use agents and skills.sh](./custom-widgets/agent-authoring) for the complete procedure and the portable Agent Skill. +The built-in [Assistant](./assistant) uses the same tool catalog with the current Homarr session and asks for approval +before mutations by default. diff --git a/apps/docs/docs/management/media/index.mdx b/apps/docs/docs/management/media/index.mdx index e55a05659..2872dbe6e 100644 --- a/apps/docs/docs/management/media/index.mdx +++ b/apps/docs/docs/management/media/index.mdx @@ -12,3 +12,5 @@ Using the media feature, you can upload images for custom icons to Homarr. Images will be stored in the database. They can be selected in the [icon picker](/docs/advanced/icons). ![](./img/screenshot.png) + +![The Media management page](../img/media.png) diff --git a/apps/docs/docs/management/search-engines/index.mdx b/apps/docs/docs/management/search-engines/index.mdx index e687a16d5..0d1ecf7c6 100644 --- a/apps/docs/docs/management/search-engines/index.mdx +++ b/apps/docs/docs/management/search-engines/index.mdx @@ -14,6 +14,8 @@ The default **Search** mode lists every configured search engine as a fallback a engines by shortcut, switch to **Web** with `!`. DuckDuckGo bang discovery is intentionally limited to Web mode so an ordinary search term never expands into similarly named bang providers. +![The Search engines management page](../img/search-engines.png) + You can add any search engine that has a search URL that accepts a search term as a parameter. ## Create search engine diff --git a/apps/docs/docs/management/settings/img/analytics.png b/apps/docs/docs/management/settings/img/analytics.png new file mode 100644 index 000000000..0ae5834f4 Binary files /dev/null and b/apps/docs/docs/management/settings/img/analytics.png differ diff --git a/apps/docs/docs/management/settings/img/appearance.png b/apps/docs/docs/management/settings/img/appearance.png new file mode 100644 index 000000000..816b4c8dc Binary files /dev/null and b/apps/docs/docs/management/settings/img/appearance.png differ diff --git a/apps/docs/docs/management/settings/img/authentication-branding.png b/apps/docs/docs/management/settings/img/authentication-branding.png new file mode 100644 index 000000000..d1542b966 Binary files /dev/null and b/apps/docs/docs/management/settings/img/authentication-branding.png differ diff --git a/apps/docs/docs/management/settings/img/crawling-and-indexing.png b/apps/docs/docs/management/settings/img/crawling-and-indexing.png new file mode 100644 index 000000000..eea22c292 Binary files /dev/null and b/apps/docs/docs/management/settings/img/crawling-and-indexing.png differ diff --git a/apps/docs/docs/management/settings/img/culture.png b/apps/docs/docs/management/settings/img/culture.png new file mode 100644 index 000000000..f43491edb Binary files /dev/null and b/apps/docs/docs/management/settings/img/culture.png differ diff --git a/apps/docs/docs/management/settings/img/global-custom-css.png b/apps/docs/docs/management/settings/img/global-custom-css.png new file mode 100644 index 000000000..701b5ee3d Binary files /dev/null and b/apps/docs/docs/management/settings/img/global-custom-css.png differ diff --git a/apps/docs/docs/management/settings/img/instance-branding.png b/apps/docs/docs/management/settings/img/instance-branding.png new file mode 100644 index 000000000..9b7ce3f14 Binary files /dev/null and b/apps/docs/docs/management/settings/img/instance-branding.png differ diff --git a/apps/docs/docs/management/settings/img/search.png b/apps/docs/docs/management/settings/img/search.png new file mode 100644 index 000000000..c7158e04e Binary files /dev/null and b/apps/docs/docs/management/settings/img/search.png differ diff --git a/apps/docs/docs/management/settings/img/users.png b/apps/docs/docs/management/settings/img/users.png new file mode 100644 index 000000000..f7f8bd7c7 Binary files /dev/null and b/apps/docs/docs/management/settings/img/users.png differ diff --git a/apps/docs/docs/management/settings/index.mdx b/apps/docs/docs/management/settings/index.mdx index e531d04f2..e3e8935fd 100644 --- a/apps/docs/docs/management/settings/index.mdx +++ b/apps/docs/docs/management/settings/index.mdx @@ -10,150 +10,100 @@ tags: # Settings -The settings page applies options to the whole Homarr application. -Some changes need a full page reload before they take effect. - -All settings sections remain visible in a single form. Click the **Save changes** button in the save bar at the bottom of the page to apply them. The save bar only appears when you have unsaved changes, and the **Discard** button reverts your changes. - -## Analytics - -Homarr uses [PostHog](https://posthog.com/) to collect anonymous usage data. -We collect this data to see what features people ACTUALLY use. -We use this data to decide where we spend our development time. - -We do not sell the data. We do not share the data with third parties. -The data does not contain personal information and does not identify you or your installation. - -Homarr sends the data to our own PostHog server at `https://hog.homarr.dev`. -The server sends the data once a week and when the server starts. - -### What we collect - -Homarr collects technical data about your installation: - -- Your Homarr version -- Your database type (SQLite, MySQL, or PostgreSQL) -- Whether Docker or Kubernetes is enabled -- Your enabled authentication providers -- Your operating system and CPU architecture -- Your default language -- The number of boards, apps, sections, layouts, users, groups, search engines, icon repositories, cron jobs, API keys, invites, sessions, and accounts -- The integration types you use and how many you have of each (for example, Sonarr or SABnzbd) -- The widget types you use and how many you have of each - -Homarr does NOT collect: - -- URLs -- Names -- Usernames, emails, or passwords -- Integration secrets or API keys -- Error messages or logs -- Any data that can identify you - -Each installation gets a random ID. We use this ID only to count unique installations. We cannot use this ID to identify you. - -Homarr does not use cookies for analytics. Homarr does not track page views automatically. Homarr only sends the data listed above. - -### Disable analytics - -Analytics are enabled by default. To disable analytics: - -1. Open the Settings page. -2. Uncheck the "Help us improve Homarr" checkbox. -3. Reload the full page. - -When analytics are disabled, Homarr does not send any data to PostHog. - -You can also set the `NO_EXTERNAL_CONNECTION` environment variable to `true`. This stops all external requests, including analytics. See the [environment variables](/docs/advanced/environment-variables) page for more information. - -You can block `hog.homarr.dev` in your DNS or firewall. Homarr cannot send data when this address is blocked. - -## Search Engine Optimization (SEO) - -Search engines use web crawlers to index websites. This can cause unwanted traffic to your dashboard. -Homarr asks crawlers to not index your instance by default. Use these settings to change this request. - -Homarr cannot control what the crawlers do. A crawler can ignore the request. Your website can still appear in an index. - -### No index - -This setting asks crawlers to not index your instance. -This setting is enabled by default. Disable this setting to allow indexing. - -### No follow - -Crawlers follow links to discover new pages. -This setting asks crawlers to not follow links. This setting is enabled by default. -Crawler behavior can differ between search engines. - -### No translate - -Some browsers offer to translate pages. -This setting asks crawlers to not offer translation. Some browsers ignore this setting. - -### No site links search box - -This setting applies to Google only. -Google can show a search box below your domain. -This setting asks Google to not show this box. This setting is disabled by default. +Settings apply to the entire Homarr instance. The save bar appears after a change; use **Save changes** to apply it or +**Discard** to revert it. Some changes require a full page reload. ## Boards -### Global home board +**Global home board** is the fallback for users without a personal home board and for anonymous users. **Global mobile +board** overrides it on mobile devices. Both must be public. -You can set a global home board. -This board is the fallback for users without their own home board. It is also the fallback for anonymous users. -The board must be public. +**Enable status by default** sets the initial status-check state for new app items. **Force disable status** turns app +status off instance-wide. -### Global mobile board +![Instance-wide board defaults](../img/settings-overview.png) -You can set a global mobile board. -Homarr shows this board on mobile devices instead of the global home board. -Homarr detects mobile devices with the User-Agent header. -The board must be public. +## Users -### App status +**Enable Gravatar** uses Libravatar or Gravatar when a user has an email address but no custom avatar. -#### Enable status by default +![Instance-wide user settings](./img/users.png) -You can decide if app status is enabled when you add a new app. +## Search -#### Force disable status +**Global default search engine** is the instance fallback. Integration-backed search engines are configured per user, +not here. -You can decide if app status is disabled on all boards. +![Global default search engine](./img/search.png) ## Appearance -### Default color scheme +**Default color scheme** is the fallback for users without a personal color-scheme preference. -You can set the default color scheme for users without their own color scheme. +![Default instance color scheme](./img/appearance.png) -## Branding +## Instance branding -Branding settings let administrators adapt Homarr to the identity and visual style of their installation. Changes apply across the application and authentication pages after you save the settings. +Branding is stored server-side and applies across the instance after saving. -### Identity +### Identity and appearance -- **Application name** replaces the default Homarr name in page titles and branded surfaces. -- **Logo** is used in the header and other application branding. -- **Favicon** controls the browser tab icon. When it is empty, Homarr falls back to the configured logo. +Set the application name, logo, browser icon, primary and secondary colors, and corner style. **Keep this color on every +board** prevents board colors from replacing the application accent. The browser icon falls back to the application +logo when empty. -### Colors and corners +Images accept HTTP(S) URLs or app-relative paths. -Choose the primary and secondary colors used by the theme. **Lock primary color** prevents users from overriding the configured primary color. **Default corner style** controls the global radius used by cards, controls, and other interface elements. +![Instance branding identity and appearance settings](./img/instance-branding.png) ### Global custom CSS -The branding settings include a CSS editor for styles that should apply across the entire instance. You can write CSS directly or import a community theme from the Workshop. CSS configured on an individual board takes precedence over the global stylesheet. +**Global custom CSS** applies to every page. Write CSS directly or import a theme from the Workshop. Board custom CSS +loads later and can override it. -### Sign-in page +![Global custom CSS editor](./img/global-custom-css.png) -You can set a greeting and a background image for authentication pages. The overlay slider adjusts the contrast between the background and the sign-in content. The visibility controls independently show or hide the application name, logo, and greeting. +See [Styling](/docs/advanced/styling) for selectors, theme variables, and board-level CSS. -Use an image URL that every user can load before signing in. A URL that requires an authenticated Homarr session will not work on the sign-in page. +### Authentication pages + +Set a greeting, background image, background overlay, and whether the application name, logo, and greeting appear on +authentication pages. + +![Authentication branding and current branding summary](./img/authentication-branding.png) ## Culture -### Default language +**Default language** is the fallback for users without a personal language preference. -You can set the default language for users without their own language. +![Default instance language](./img/culture.png) + +## Crawling and indexing + +These options set crawler directives: + +- **No index** asks crawlers not to index the instance. +- **No follow** asks crawlers not to follow links. +- **No translate** asks supported services not to offer translated search results. +- **No site links search box** asks Google not to add a search box to the result. + +Crawlers can ignore these requests. + +![Crawler directives](./img/crawling-and-indexing.png) + +## Analytics + +When **Help us improve Homarr** is enabled, Homarr sends analytics to its PostHog server at `https://hog.homarr.dev`. +The weekly server report also runs when Homarr starts. + +The report contains the Homarr version, database and platform details, enabled authentication providers, default +language, and counts or types of configured resources such as boards, apps, widgets, integrations, users, and groups. +Selected setup flows also send coarse events such as the entry point, intent, outcome, and elapsed time. + +Homarr does not send names, URLs, usernames, email addresses, credentials, integration secrets, API keys, logs, or error +messages. Browser page views, page leaves, and automatic interaction capture are disabled. + +Disable the setting and reload the page to stop analytics. `NO_EXTERNAL_CONNECTION=true` blocks analytics together with +all other external requests. See [Environment variables](/docs/advanced/environment-variables). + +![Analytics setting](./img/analytics.png) diff --git a/apps/docs/docs/management/tasks/index.mdx b/apps/docs/docs/management/tasks/index.mdx index c47eb1a74..036ad55e9 100644 --- a/apps/docs/docs/management/tasks/index.mdx +++ b/apps/docs/docs/management/tasks/index.mdx @@ -7,34 +7,16 @@ tags: # Tasks -Homarr has background jobs for various tasks, most of them are for realtime widget updates. -The tasks page allows you to run background jobs manually and configure them. +The tasks page controls scheduled background jobs used by integrations and widgets. It is available to administrators +under **Management → Tools → Tasks**. -![Tasks page](./img/tasks.png) +Each task exposes: -## Opening the tasks page +- its current status and schedule; +- a cron-based schedule interval; +- a manual run action; +- an enable or disable action. -Navigate to `Management` > `Tools` > `Tasks`. -The page is only accessible to users with admin permission. +![The scheduled Tasks management page](../img/tasks.png) -## Changing interval - -In the column `Schedule interval` you can change the interval in which the task runs. -Different intervals are available, such as `1 minute`, `5 minutes`, `10 minutes`, `30 minutes`, and `1 hour`. -All intervals are cron expressions, which means it will run the next time the cron expression matches the current time. - -## Actions - -You can find different actions for each task on the right side of a task item. - -### Run Manually - -To run a task manually, click the "Play" button, which will execute the task immediately. -During the exection the badge will show `Running`. - -### Disabling / Enabling - -You can disable a task by clicking the "Power" button, which will change it to a "Power-Off" button. -When a task is disabled, it will not run automatically according to its schedule. -You can enable it again by clicking the "Power-Off" button, which will change it back to a "Power" button. -Running a task manually is still possible when it is disabled. +Disabling a task stops scheduled runs but does not prevent a manual run. diff --git a/apps/docs/docs/management/users/index.mdx b/apps/docs/docs/management/users/index.mdx index 9c32ba56f..00fc8ac67 100644 --- a/apps/docs/docs/management/users/index.mdx +++ b/apps/docs/docs/management/users/index.mdx @@ -9,289 +9,65 @@ tags: # Users -Each person accessing Homarr is a user. Using the users management you can configure who has access to certain resources. -A user may have multiple sessions on different devices and can log in from multiple locations at the same time. -A user can be assigned to multiple groups. +A **user** is a Homarr identity with preferences, sessions, group memberships, and optional resource access. Homarr can +use local credentials, LDAP, or OIDC; see [Single sign-on](/docs/advanced/single-sign-on). -:::tip +Manage users under **Management → Users → Manage**. Administrators can change a user's profile, language, home boards, +search preferences, week start, accessibility preference, and local password. Deleting a user does not delete boards +they created. -Homarr supports [single sign on for easier and seamless authentication](/docs/advanced/single-sign-on) (e.g. Authelia). - -::: - -## Manage users - -### Creating new users - -To create new users, you must navigate to `Mangement` > `Users` > `Manage` and click on the create button to create a new one: \ -![](./img/button-create-user.png) - -You'll be guided through the process using a wizard: \ -![](./img/create-wizard.png) - -The username and Email must be unique. A username is required. -When creating a password, you must meet the password requirements: \ -![](./img/password-requirements.png) - -After you completed all steps, you can start over to create another user or choose to go back to the list: \ -![](./img/wizard-complete.png) - -## Editing a user - -A user can be edited on the `Mangement` > `Users` > `Manage` page when you click on the username. -Here you'll have access to two tabs: **General** and **Security**. - -### General tab - -#### Username - -This is the unique username that identifies this user. It can be changed to anything but must be at least 3 characters long with a limit of 255 characters. -This name will be used for the credential's login. It is also used to auto-generate profile pictures if no picture was uploaded. - -#### E-Mail - -This is the unique email of the user. As of 1.0, it is not used for any notifications and only for organizational purposes. -This field is optional. - -#### Language - -This is the currently selected language of the user. -Changing the language will change all text & the right to left (RTL) feature in some languages. -By default, Homarr will choose English as the default language. Here you can override the language for this specific user. -The user may choose a different language by themselves afterward. - -#### Home board - -Optional field for the board that is loaded by default if no board was specified in the URL. -Only boards that the user has permission to are being shown. - -#### Search - -Options to configure default search engine of user and whether to open search results in a new tab. - -#### First day of the week - -Choose the first day of the week for the user. This will affect the calendar widget. - -#### Accessibility - -Option to show icons for status check instead of colored dots. - -#### Delete - -This action will permanently delete the user from the database, including any preferences they set. -If the user created boards, they wil **not** be deleted. -This action is **irreversible** and cannot be undone. All data is permanently lost. - -### Security tab - -#### Change password - -Here the password for this user can be changed. -It must also meet the password requirements of Homarr. -The password is stored as an encrypted value with a salt in the database - this means the value cannot be read out from the database afterward. -You must take care of sending the new password to the user. -This functionality can also be useful to lock out a bad actor without tampering with any data (except the password hash). -For security reasons, you must confirm the password a second time. +![The Users management page](../img/users.png) ## Groups -Using groups, you can manage the permissions of users. -Members can be directly assigned to groups. +Groups provide permissions and default desktop or mobile home boards. A user receives permissions from every group they +belong to. The `Everyone` group automatically contains every user and cannot be renamed or have members removed. -A user will have the permissions of all groups they are a member of. -Some permissions include other permissions, for example the "Full board access" permission includes all board permissions. +![The user groups management page](../img/users-groups.png) -By default, a group called "credentials-admin" will be generated where the first user will be placed. -However, you can create as many groups as you'd like. +Group order controls preference defaults when a user belongs to several groups. Permissions are cumulative across +groups; a more privileged group cannot be cancelled by a less privileged one. -### Creating a group +## Permission model -Click on the button `New group` to create a new one. -The group-name form expands above the group list and can be closed without leaving the page. +Most resource categories combine an access level with separate capabilities such as creation. -### Managing a group +| Category | Access levels, from lowest to highest | Separate capabilities | +| -------------- | ----------------------------------------- | --------------------- | +| Boards | View all → Modify all → Full access | Create boards | +| Apps | Modify all → Full access | Use all, create apps | +| Integrations | Use all → Interact with any → Full access | Create integrations | +| Search engines | Modify all → Full access | Create search engines | +| Media | View all → Full access | Upload media | +| Other | View logs | — | +| Administration | Administrator | — | -#### General tab +Higher levels include the lower levels in the same category. **Administrator** grants every permission and disables the +other permission controls. -##### Name +Apps are an exception: modifying every app does not by itself allow using every app on a board. Grant **Use all apps** +or full app access when both behaviors are required. -Name for the group that can be chosen freely. +The Viewer, Editor, and Admin presets fill common permission sets. **Effective permissions** shows the complete result, +including inherited permissions. -##### Transfer ownership +Custom Widget management, import, preview, secrets, Workshop installation, and placement configuration require an +administrator. Normal board permissions still control viewing and using a placed Custom Widget. -Every group has an owner. Using this button, the ownership can be transferred to a different user. -Group ownership is only organizational. +## Resource access -##### Delete +Global group permissions apply to every resource in a category. Boards and integrations can also grant access to +specific users or groups: -Deletes the group permanently. This change is irreversible. +- Board access uses View, Modify, and Full levels. +- Integration access uses Use, Interact, and Full levels. -#### Settings tab +See [Boards](../boards#access-control) and [Integrations](../integrations#permissions). -In this tab, you can configure some settings for the group. Those settings will be prioritized by the order of the groups on the groups list page +## Invitations -##### Priorization +Invitations let a user create a local-credentials account before an expiry time. They require the credentials +authentication provider. -The higher a group in the list, the higher the priority. This means that if a user is in multiple groups, the permissions of the group with the highest priority will be used. -It will always fallback to the everyone group if no other group permissions are set. - -![](./img/groups-list.png) - -##### Boards - -Configure board settings for a group. User specific settings will override group settings. - -###### Home board - -The board that is loaded by default if no board was specified in the URL. - -###### Mobile board - -The board that is loaded by default on mobile devices. - -#### Members tab - -In this tab, you can assign users to the group. With the button at the top right, a new member can be added to the group: - -![](./img/add-group-member.png) - -Members can be removed from the group using the remove button at the end: - -![](./img/remove-group-member.png) - -#### Permissions tab - -In this tab, you manage what permissions the members of this group will have. -Permissions are shown as a matrix with one row per category (boards, apps, integrations, and so on). Each row has a -segmented control that lets you pick a single **access level**, plus a checkbox for each **capability** the category -has. - -Levels in a category are cumulative: selecting a level grants that level and every level below it in the same -category. Choosing **No access** grants no access level for that category. - -##### Capabilities are separate from the access level - -A capability is something you can grant on its own, independently of how much of everyone else's data the members -can see. Creating is the usual example: you can let members create their own boards without letting them view or -modify anyone else's boards. Apps additionally have **use all apps**, which lets members put any app on a board -without being able to edit apps. - -Some access levels already include a capability through permission inheritance (marked in the table below); the -checkbox is then ticked, disabled, and explains which level includes it. - -##### Administration - -Selecting the **Administrator** level grants full access to everything. While it is selected, every other category -is disabled and explains that administrators already have that access. Setting the administrator row back to -**No access** re-enables the other categories with the selections they had before. - -##### Access levels - -The access levels below are cumulative, in ascending order, with the category's capabilities listed separately: - -| Category | Access levels (ascending) | Capabilities | Already included at | -| -------------- | ---------------------------------------------------------------------------------------- | ------------------------------- | ---------------------------------------------------- | -| Boards | view all boards → modify all boards → full board access | create boards | full board access | -| Apps | modify all apps → full app access | use all apps, create apps | create apps: modify all apps and full app access; use all apps: full app access | -| Integrations | use all integrations → interact with any integration → full integration access | create integrations | full integration access | -| Search engines | modify all search engines → full search engine access | create search engines | modify all search engines, full search engine access | -| Medias | view all medias → full media access | upload medias | full media access | -| Other | view logs | — | — | -| Administrator | administrator | — | — | - -Apps are the one category where "use" is not a level. Being able to modify every app does **not** imply being able -to put any app on a board — only full app access grants both — so the two are kept independent rather than stacked, -and picking **Modify** never silently grants use of every app. - -The levels grant the following: - -- **Boards**: view all boards; modify all boards (not access control and danger zone); full board access (view, modify and delete every board, including access control and the danger zone). -- **Apps**: modify all apps; full app access (manage, use and delete any app). -- **Integrations**: use all integrations; interact with any integration; full integration access (manage, use and interact with any integration). -- **Search engines**: modify all search engines; full search engine access (manage and delete any search engine). -- **Medias**: view all medias; full media access (manage and delete any media). -- **Other**: view logs. - -##### Presets - -Above the rows you can apply a preset to fill in a common configuration in one click: - -- **Viewer**: read-only - view all boards and medias, use any app on a board, and use existing integrations. -- **Editor**: day-to-day management - modify all boards and apps, create boards and integrations, interact with any integration, modify search engines, and upload medias, without deleting resources or managing access. -- **Admin**: grants the administrator permission (full access to everything). - -When the current selection does not match any preset, a **Custom** badge is shown. - -##### Also grants - -Some levels include additional permissions automatically. When a level implies extra permissions (for example, -modifying all apps also allows creating apps), a dimmed **Also grants: …** hint is shown below the category row, -listing the implied permissions. - -##### Effective permissions - -Below the rows, the **Effective permissions** panel can be expanded to review everything members of this group will -be able to do - the full, de-duplicated set of permissions, including everything granted indirectly through the -levels - grouped by category, with a count for each. - -Custom Widget authoring, import, migration, preview, secrets, Workshop access, and placement configuration are reserved -for administrators and are not separate assignable group permissions. Board modifiers can still move, resize, change -presentation settings, or remove an existing Custom Widget placement, and board viewers can use placed widgets as -allowed by each request. - -When you changed permissions, you must confirm your changes by clicking the banner at the bottom: - -![](./img/changing-group-permissions.png) - -#### Special groups - -Currently one special group exists. This group is `everyone`. It automatically adds every user that is known to Homarr to its members. Neither its name nor its members can be changed. - -## Invites - -Invites are an easy-to-use system to allow users to onboard themselves. -It is useful in companies or large-scale homelabs where many users must be onboarded at the same time. -You should trust the end user that they enter their data truthfully as the administrator will not confirm the entered data after the user has completed the onboarding. - -This feature can only be used when credentials authentication is enabled. -An invitation link can be used indefinitely. - -### Creating an invitation - -Select the create-invitation button. The expiration form expands above the invitation table instead of opening a -dialog or navigating to another page: - -![](./img/create-invitation-button.png) - -Next, define the expiration time for this invitation. They will expire after some time and will no longer be valid. -It must be at least 1 hour in the future and at max 6 months in the future. -The default is 4 hours in the future. - -![](./img/invitation-expiry-date.png) - -Next, click `Create` and the same section shows the ID, Token and a link that can be copied: - -![](./img/create-invitation-confirmation.png) - -Both ID and Token are also in the URL. Ensure that you copy either ID & Token or the URL - it will never be shown again. -Use **Copy** to copy the URL, then close the section when you are finished. - -### Self-onboarding - -Clicking the invitation link opens a centered registration form that uses the same visual shell as Homarr's onboarding -and sign-in pages, with fields for the username and password: - -![](./img/invitation-self-onboarding.png) - -At the bottom of the page, the user who created the invitation can be seen. - -### Deleting an invitation - -If an invitation needs to be deleted before or after the expiry, the delete button at the end of the table can be used: - -![](./img/deleting-invitation.png) - -The link will become invalid. -If the invitation expires, the link will also expire. -The first click changes the action to **Confirm**; the second click deletes the invitation without opening a dialog. +Create an invitation under **Management → Users → Invitations**, choose an expiry, and copy the generated URL. The token +is shown once. Deleting the invitation or reaching its expiry invalidates the URL. diff --git a/apps/docs/docs/widgets/air-quality/index.mdx b/apps/docs/docs/widgets/air-quality/index.mdx index 1e37bbd3b..cec98eac2 100644 --- a/apps/docs/docs/widgets/air-quality/index.mdx +++ b/apps/docs/docs/widgets/air-quality/index.mdx @@ -13,17 +13,8 @@ import { airQualityWidget } from "."; -The Air Quality & UV widget shows the current air quality index for a selected location. It adds the UV index, -dominant pollutant, particulate matter and the highest available pollen reading as space allows. Open the advanced -view for a 24-hour AQI and UV chart, all available pollutant and pollen readings, and seven-day daily maxima. - -Select the European or US AQI scale, or use the automatic setting. Automatic uses the US scale for viewers whose -locale region is the United States and the European scale everywhere else. The selected scale stays in widget options -instead of being repeated beside every reading. Pollen values are individual measured concentrations; the widget does -not combine them into a single pollen index. - -The categories and colors summarize published index bands and are not medical advice. Pollutant concentrations use -micrograms per cubic meter (`µg/m³`), and pollen uses grains per cubic meter. +The Air Quality & UV widget shows current and forecast AQI, UV, pollutant, and pollen data for a location. Choose the +European or US AQI scale; automatic mode uses the US scale for US locales and the European scale elsewhere. @@ -37,11 +28,8 @@ micrograms per cubic meter (`µg/m³`), and pollen uses grains per cubic meter. ### Data source -Homarr uses the free Open-Meteo Air Quality API. The widget refreshes active data every 15 minutes and requests a -seven-day forecast for European AQI, US AQI, UV, particulate matter, ozone, nitrogen dioxide, sulphur dioxide, carbon -monoxide, and available alder, birch, grass, mugwort, olive and ragweed pollen. Identical location requests reuse the -server response for 15 minutes. If a refresh fails, Homarr can keep a recent successful response visible for up to 24 -hours instead of replacing it with an empty state. +Data comes from the Open-Meteo Air Quality API and refreshes every 15 minutes. A recent successful response can remain +visible for up to 24 hours when the API is unavailable. Set `NO_EXTERNAL_CONNECTION=true` to disable this and other internet-backed requests. If you need to allowlist the service, use `https://air-quality-api.open-meteo.com`. diff --git a/apps/docs/docs/widgets/app/img/github.png b/apps/docs/docs/widgets/app/img/github.png deleted file mode 100644 index 71c400a26..000000000 Binary files a/apps/docs/docs/widgets/app/img/github.png and /dev/null differ diff --git a/apps/docs/docs/widgets/app/img/jellyseerr-description-tooltip.png b/apps/docs/docs/widgets/app/img/jellyseerr-description-tooltip.png deleted file mode 100644 index 01ddc2686..000000000 Binary files a/apps/docs/docs/widgets/app/img/jellyseerr-description-tooltip.png and /dev/null differ diff --git a/apps/docs/docs/widgets/app/img/pi-hole-ping-icon.png b/apps/docs/docs/widgets/app/img/pi-hole-ping-icon.png deleted file mode 100644 index 0f177d595..000000000 Binary files a/apps/docs/docs/widgets/app/img/pi-hole-ping-icon.png and /dev/null differ diff --git a/apps/docs/docs/widgets/app/index.mdx b/apps/docs/docs/widgets/app/index.mdx index 3c7231fdc..fde54d943 100644 --- a/apps/docs/docs/widgets/app/index.mdx +++ b/apps/docs/docs/widgets/app/index.mdx @@ -11,25 +11,8 @@ import { appWidget } from "."; -The app widget allows you to add a link to an application or a website that you want to access quickly from your Homarr board. Compact tiles retain the familiar title, optional description, and centered app icon proportions. -It also supports a status check to indicate whether Homarr can reach the application or website. - -### Screenshots - -import githubApp from "./img/github.png"; -import jellyseerrApp from "./img/jellyseerr-description-tooltip.png"; -import piHoleApp from "./img/pi-hole-ping-icon.png"; - -
- app github with-status-check - app pi-hole with-status-check status-check-icon - app jellyseerr with-description-tooltip -
- -### Interactions - -App tiles stay compact and open their configured destination directly. They do not use the shared widget context menu; -configure the app and its status check from the tile's edit actions. +The App widget opens an application or website and can show whether Homarr can reach it. Configure the target and status +check from the tile's edit actions. ### Adding the widget diff --git a/apps/docs/docs/widgets/archive-team-warrior/index.mdx b/apps/docs/docs/widgets/archive-team-warrior/index.mdx index b247b2d53..e00bb5503 100644 --- a/apps/docs/docs/widgets/archive-team-warrior/index.mdx +++ b/apps/docs/docs/widgets/archive-team-warrior/index.mdx @@ -14,7 +14,8 @@ import { archiveTeamWarriorWidget } from "."; -Use this widget to see what your ArchiveTeam Warrior is preserving without leaving Homarr. The compact view keeps the current project, runner state, job counts, bandwidth, and optional broadcast message visible. Advanced view adds the complete active-job list, job start times, project and bandwidth-session identifiers, session transfer totals, exact update time, and the full broadcast message whenever one is available. A failed refresh keeps the last snapshot visible with a stale-data warning. +The ArchiveTeam Warrior widget shows the current project, runner state, jobs, bandwidth, and broadcast message. Advanced +view adds active-job and session details. A failed refresh keeps the last snapshot with a stale-data warning. ### Supported integration diff --git a/apps/docs/docs/widgets/assistant/index.mdx b/apps/docs/docs/widgets/assistant/index.mdx index 4f719cc6f..e92cde43a 100644 --- a/apps/docs/docs/widgets/assistant/index.mdx +++ b/apps/docs/docs/widgets/assistant/index.mdx @@ -1,36 +1,21 @@ --- title: "Assistant" -description: "Have a complete assistant conversation directly on a board." +description: "Have an Assistant conversation directly on a board." hide_title: true --- import { AddingWidget } from "@site/src/components/widgets/adding"; import { WidgetHeader } from "@site/src/components/widgets/header"; import { assistantWidget } from "."; -import assistantWidgetImage from "../../management/img/assistant-widget.png"; -The Assistant widget puts the app-wide assistant on a board. It uses the same active conversation as the user-menu and -command-menu surfaces, so messages and approvals stay synchronized. +The Assistant widget provides the same active conversation as the app-wide Assistant. Messages, tool calls, and +approvals stay synchronized between surfaces. -An administrator must first configure and enable Assistant in **Management → Assistant**. Signed-out users are prompted -to sign in, while an incomplete or disabled configuration shows an unavailable state. - -Assistant widget embedded on a dashboard with its conversation header, automatic approvals control, model selector, and composer +An administrator must first configure [Assistant](/docs/management/assistant). Short widget layouts show an action to +open the full Assistant instead of compressing the conversation. ### Adding the widget - -The default size is ten columns by four rows and shrinks to fit narrower boards. Short layouts show an **Open -assistant** action instead of compressing the conversation controls; increase the widget height to keep the complete -conversation inline. - -Responses continue when the widget leaves the viewport. Drafts and attachments remain local to each visible Assistant -surface, and private conversation data is never stored in board settings. Normal Homarr permissions and approval rules -still apply to every action. diff --git a/apps/docs/docs/widgets/bookmarks/index.mdx b/apps/docs/docs/widgets/bookmarks/index.mdx index 9c22f1bae..db2dc85a5 100644 --- a/apps/docs/docs/widgets/bookmarks/index.mdx +++ b/apps/docs/docs/widgets/bookmarks/index.mdx @@ -13,12 +13,8 @@ import { bookmarksWidget } from "."; -The bookmarks widget keeps direct URLs and Homarr Apps in one ordered list. -Paste a URL and press Enter, paste several comma-separated or one-per-line URLs, or search for an existing App. -URLs do not need an App record; Homarr uses the site's favicon and falls back to a link icon when it cannot load one. -Bookmarks selected from Apps continue to use the App name, URL, icon, and description. - -**Adaptive** layout is the practical default: it changes between icons, compact rows, and tiles as the widget changes shape. **Compact grid** keeps every card to a short row. Enable **Expand cards to fill row** when cards in an incomplete final row should use the remaining width. Every compact item exposes its destination on hover, while advanced view expands items into descriptive cards. +The Bookmarks widget keeps direct URLs and Homarr Apps in one ordered list. URLs do not require an App record; Homarr +uses the site's favicon when available. Choose adaptive, compact-grid, or other layouts from the widget configuration. ### Screenshots diff --git a/apps/docs/docs/widgets/calendar/index.mdx b/apps/docs/docs/widgets/calendar/index.mdx index 82d8a1cbd..5af2b7c85 100644 --- a/apps/docs/docs/widgets/calendar/index.mdx +++ b/apps/docs/docs/widgets/calendar/index.mdx @@ -1,6 +1,6 @@ --- title: "Calendar" -description: "Display events from your integrations in a calendar view within a certain relative time period" +description: "Display calendar events and upcoming media releases." hide_title: true --- @@ -10,9 +10,6 @@ import { WidgetHeader } from "@site/src/components/widgets/header"; import { AddingWidget } from "@site/src/components/widgets/adding"; import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetIntegrations } from "@site/src/components/widgets/integrations"; -import { IconAd } from "@tabler/icons-react"; -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; import { calendarWidget } from "."; import { lidarrIntegration } from "@site/docs/integrations/lidarr"; import { nextcloudIntegration } from "@site/docs/integrations/nextcloud"; @@ -21,58 +18,40 @@ import { radarrIntegration } from "@site/docs/integrations/radarr"; import { readarrIntegration } from "@site/docs/integrations/readarr"; import { sonarrIntegration } from "@site/docs/integrations/sonarr"; import { icalIntegration } from "@site/docs/integrations/ical"; - - - -The calendar widget shows a month view of events from different integrations. -It allows you to view calendar events or upcoming releases from your media managers. -Calendar requests use normal human month numbers (`1` for January through `12` for December), including when -the same data is requested through Homarr's MCP or Assistant tools. - -### Screenshots - import currentView from "./img/current-view.png"; import advancedView from "./img/advanced-view.png"; -
- Calendar month view with marked events - Calendar advanced view with grouped events -
+ -### Supported Integrations +The Calendar widget combines events and upcoming releases in a month view. Advanced view shows a grouped event list with +source, title, location, and description. Healthy integrations remain visible when another source fails. + +### Month view + +Calendar month view with marked events + +### Advanced view + +Calendar advanced view with grouped events + +### Supported integrations ### Interactions -- Colored dots directly below a date mark its events. They scale with the widget and are hidden when the calendar is too short. -- Hover over a marked date to preview its events in a popover. -- The advanced view replaces the month grid with a grouped event list, keeps every event attributed to its source integration, and expands titles, locations, and descriptions. Use its previous and next controls to change months. -- If one selected integration is unavailable, its warning indicator remains visible while events from healthy integrations continue to load. +- Hover or select a marked date to inspect its events. +- Use advanced view to browse grouped events by month. diff --git a/apps/docs/docs/widgets/clock/index.mdx b/apps/docs/docs/widgets/clock/index.mdx index 1f453d33f..349ec3e08 100644 --- a/apps/docs/docs/widgets/clock/index.mdx +++ b/apps/docs/docs/widgets/clock/index.mdx @@ -13,27 +13,8 @@ import { clockWidget } from "."; -The clock widget displays the current date and time in a customizable format. - -Advanced view turns it into a World Clock. The configured primary timezone stays prominent while New York, Paris, and -Tokyo are included as secondary defaults. You can add, rename, remove, and reorder up to six cities in widget options; -London, Sydney, and UTC are also available as quick presets. - -The digital advanced view keeps the primary timezone prominent and presents every secondary city as a concise, -comparable card. The primary clock includes a segmented 24-hour rail with a current-time marker, elapsed and remaining -time, six-hour ticks, and a legend for night, dawn, day, and dusk. These phases are based on local clock time and are not -astronomical sunrise or sunset calculations. Secondary cards stop after their localized date and timezone offsets. - -The compact widget remains a single numeric clock. The time-format selector shows common Day.js presets with live -examples and applies to the primary clock. Choosing a format with seconds enables second-level updates; 12-hour and -24-hour display are selected through those same formats. The date-format selector likewise -shows live Day.js examples and their tokens. Secondary cities always include a short localized date and a -Yesterday, Today, or Tomorrow label relative to the primary timezone. UTC and relative offsets follow current timezone -rules, including daylight-saving changes. - -Weather remains optional and uses its own configured location rather than a World Clock city. Its icon is static by -default and can be animated explicitly; reduced-motion preferences always disable animation. An unsupported saved -timezone is identified without preventing valid clocks from rendering. +The Date and time widget shows a configurable clock and optional weather. Advanced view adds a world clock with up to +six named timezones. Time and date formats use Day.js tokens and follow current timezone and daylight-saving rules. ### Screenshots diff --git a/apps/docs/docs/widgets/coolify/index.mdx b/apps/docs/docs/widgets/coolify/index.mdx index 71b1081a0..f6013fe94 100644 --- a/apps/docs/docs/widgets/coolify/index.mdx +++ b/apps/docs/docs/widgets/coolify/index.mdx @@ -15,7 +15,7 @@ import { coolifyIntegration } from "@site/docs/integrations/coolify"; -The Coolify widget displays a compact overview of your Coolify instance. It can show servers, applications, and services with status indicators, project and environment context, direct links to Coolify, and the installed Coolify version. Compact resource badges and footer details remain visible without height-based hiding. +The Coolify widget shows servers, applications, and services with their status, project, environment, and Coolify links. ### Supported Integrations @@ -27,9 +27,8 @@ The Coolify widget displays a compact overview of your Coolify instance. It can ]} /> -Advanced view opens the Servers, Applications, and Services sections regardless of their compact visibility switches. It identifies each Coolify integration, shows server `is_reachable` and `is_usable` values, and lists applications nested in services when the API provides them. Healthy integrations remain visible if another source fails, with the failed source identified by a warning. - -IP addresses remain masked in advanced view until you explicitly use the eye control. Public resource, Coolify dashboard, and log links retain the widget's safe new-tab handling. +Advanced view shows all sections, source integrations, reachability fields, and nested applications. IP addresses remain +masked until revealed. Healthy integrations remain visible when another source fails. @@ -49,8 +48,4 @@ IP addresses remain masked in advanced view until you explicitly use the eye con | **Applications** | Lists applications with runtime status, project and environment context, public URL links, Coolify dashboard links, and log links. | | **Services** | Lists services with runtime status, project and environment context, public URL links, Coolify dashboard links, and log links. | -### Notes - -- The widget supports one or more Coolify integrations. With multiple integrations, each instance is shown as a separate card. -- The Coolify API token is team-scoped. Homarr only shows resources available to the team where the token was created. -- Data is cached for 30 seconds and refreshed in the background. +The Coolify API token is team-scoped; Homarr shows only resources available to that team. diff --git a/apps/docs/docs/widgets/countdown/index.mdx b/apps/docs/docs/widgets/countdown/index.mdx index 268e1b7ba..d78818c00 100644 --- a/apps/docs/docs/widgets/countdown/index.mdx +++ b/apps/docs/docs/widgets/countdown/index.mdx @@ -13,25 +13,11 @@ import { countdownWidget } from "."; -The Countdowns widget tracks up to 20 events without an integration. Add each event in widget options, choose its local -date and time, and select an IANA timezone. Events can be reordered by dragging them. +The Countdowns widget tracks up to 20 one-time or yearly events without an integration. Events use an IANA timezone and +can be reordered; the first event is shown in compact view. -The compact widget shows the first configured event, so dragging an event to the top selects the countdown displayed on -the board. Advanced view uses that same event for its larger summary and preserves the configured order within its -upcoming and completed groups. List cards keep their occurrence date at the bottom, below the optional progress bar. - -One-time events remain completed after their target. A yearly event keeps the same local date and wall-clock time in its -configured timezone, including when daylight-saving offsets change. A February 29 event waits until the next leap year. -If a configured local time falls in a daylight-saving gap, the first valid time afterward is used; if it occurs twice, -the earlier occurrence is used. - -Progress is optional. One-time events need a start date before a percentage can be calculated. Yearly events show -progress from the previous occurrence to the next. When enabled, seconds remain visible for every upcoming event. - -Browser notifications are an optional local preference in advanced view and are disabled by default. Permission is -requested only after you enable notifications, and alerts can fire once per occurrence while Homarr is open. Browser -storage uses the board and widget identifiers to keep preferences separate and prevent duplicate alerts; clearing site -data resets them. Widget previews do not persist alert preferences. +Optional progress uses the configured start date. Browser notifications are local to the current browser and can fire +only while Homarr is open. diff --git a/apps/docs/docs/widgets/custom-api/index.mdx b/apps/docs/docs/widgets/custom-api/index.mdx index d7eb59617..d229cf715 100644 --- a/apps/docs/docs/widgets/custom-api/index.mdx +++ b/apps/docs/docs/widgets/custom-api/index.mdx @@ -1,63 +1,34 @@ --- title: "Custom API" -description: "Displays data from a custom API endpoint using configurable display types and optional JSX templates." +description: "Displays data from a custom API using a safe JSX template." hide_title: true --- -import { WidgetInteractionGuide } from "@site/src/components/widgets/interactions"; - import { WidgetHeader } from "@site/src/components/widgets/header"; import { AddingWidget } from "@site/src/components/widgets/adding"; import { customApiWidget } from "."; -A definition contains API sources, named requests, a widget options schema, and one safe JSX template. - -Temporary inputs exist only while the tile is mounted. Homarr encrypts source credentials separately. - -Homarr does not send these credentials to the browser. Homarr does not include them in an export. - - +A Custom API widget renders a saved [Custom Widget definition](/docs/management/custom-widgets). The definition provides +API sources, named requests, widget options, and safe JSX. Credentials remain encrypted on the server. ### Adding the widget -Select a definition from the searchable picker. Configure its generated widget options. - -Select a refresh interval. The board item stores the definition ID and the validated widget option values. - -Credentials remain on the server. +Select a definition, configure its generated options, and choose a refresh interval. :::note -Custom API widgets must first be created in **Management → Custom Widgets** before they appear in the widget picker. -Action buttons require the request's minimum board permission, which is `modify` by default. Anonymous viewers cannot run -mutations. DELETE additionally requires full permission and confirmation. +Custom Widgets must be created under **Management → Custom Widgets** before they appear in the widget picker. ::: -### Permissions and actions +### Permissions and requests -Each named request declares its minimum board permission. This permission does not depend on the HTTP method. +Each request declares its minimum board permission. Public boards may run queries for anonymous viewers, but actions +require authentication. DELETE actions require full board permission and confirmation. -Anonymous visitors can load queries from a Custom API widget on a public board. Definitions placed only on private -boards remain unavailable to them. +The refresh interval reruns load queries. Manual queries run through `SubFetch`; successful actions can invalidate their +declared queries. -Queries and actions can use GET, POST, PUT, or PATCH. DELETE is valid only for actions so it can never run -automatically while a board loads. The `kind` value controls the remaining runtime behavior. - -A DELETE request requires full board permission and confirmation. An anonymous viewer cannot run an action. - -Homarr disables interactive controls in board edit mode. An action runs only after a user action. - -Mounting, refresh polling, and automatic retries do not run actions. An authoring preview simulates actions by default. - -An administrator can enable live actions for the short preview session. - -### Refresh behavior - -The refresh interval runs load queries again. `SubFetch` runs manual queries. - -Each query can declare a cache duration. A successful action can invalidate only its declared queries. - -Read [Custom Widgets management](/docs/management/custom-widgets) for authoring, widget options, named requests, Mantine, network scopes, and security limits. +See [Custom Widgets](/docs/management/custom-widgets) for authoring, network scopes, and security limits. diff --git a/apps/docs/docs/widgets/dns-hole-controls/index.mdx b/apps/docs/docs/widgets/dns-hole-controls/index.mdx index e9b9667cb..d1fa33b3b 100644 --- a/apps/docs/docs/widgets/dns-hole-controls/index.mdx +++ b/apps/docs/docs/widgets/dns-hole-controls/index.mdx @@ -4,15 +4,10 @@ description: "Control Pi-hole, AdGuard Home, or Technitium DNS from your dashboa hide_title: true --- -import { WidgetInteractionGuide } from "@site/src/components/widgets/interactions"; - import { WidgetHeader } from "@site/src/components/widgets/header"; import { AddingWidget } from "@site/src/components/widgets/adding"; import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetIntegrations } from "@site/src/components/widgets/integrations"; -import { IconAd } from "@tabler/icons-react"; -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; import { dnsHoleControlsWidget } from "."; import { adguardHomeIntegration } from "@site/docs/integrations/adguard-home"; import { piHoleIntegration } from "@site/docs/integrations/pi-hole"; @@ -20,9 +15,8 @@ import { technitiumDnsIntegration } from "@site/docs/integrations/technitium-dns -When several DNS integrations are selected, Homarr keeps healthy controls available if one source fails and shows a warning identifying the unavailable integration. - -This widget lets permitted users enable, disable, or temporarily pause one or more DNS services. It shares the summary query and cache with DNS Hole Summary. Every selected source stays available in the normal scrollable view, with its familiar textual status control retained at compact heights. Bulk actions keep successful results visible and report the number of failures. +The DNS Hole Controls widget enables, disables, or temporarily pauses one or more DNS services. Actions require Interact +access. Healthy controls remain available when another selected integration fails. ### Screenshots @@ -55,8 +49,6 @@ import smallSize from "./img/small.png"; - Apply an action to all available services from the top action row. Homarr keeps successful results visible and reports how many sources failed. - Interaction controls only appear when the current user has permission for that integration. - - ### Adding the widget diff --git a/apps/docs/docs/widgets/dns-hole-summary/index.mdx b/apps/docs/docs/widgets/dns-hole-summary/index.mdx index abd9d093d..8f7e76437 100644 --- a/apps/docs/docs/widgets/dns-hole-summary/index.mdx +++ b/apps/docs/docs/widgets/dns-hole-summary/index.mdx @@ -4,22 +4,16 @@ description: "Displays the summary of your DNS Hole." hide_title: true --- -import { WidgetInteractionGuide } from "@site/src/components/widgets/interactions"; - import { WidgetHeader } from "@site/src/components/widgets/header"; import { AddingWidget } from "@site/src/components/widgets/adding"; import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetIntegrations } from "@site/src/components/widgets/integrations"; -import { IconAd } from "@tabler/icons-react"; -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; import { dnsHoleSummaryWidget } from "."; -When several DNS integrations are selected, Homarr keeps healthy sources visible if one source fails and shows a warning identifying the unavailable integration. - -This widget combines statistics from every selected DNS service, including total queries, blocked queries, and blocklist size. Its data is cached under the same DNS query family as DNS Hole Controls, so placing both widgets on a board does not create a second integration request. When the widget has enough room, it adds a scrollable status row naming each selected source. +The DNS Hole Summary widget combines total queries, blocked queries, and blocklist size from selected DNS services. +Healthy sources remain visible when another integration fails. ### Screenshots @@ -54,8 +48,6 @@ import { technitiumDnsIntegration } from "@site/docs/integrations/technitium-dns ]} /> - - ### Adding the widget diff --git a/apps/docs/docs/widgets/docker-containers/index.mdx b/apps/docs/docs/widgets/docker-containers/index.mdx index 65b3a9051..ba4003ef1 100644 --- a/apps/docs/docs/widgets/docker-containers/index.mdx +++ b/apps/docs/docs/widgets/docker-containers/index.mdx @@ -7,15 +7,15 @@ hide_title: true import { WidgetHeader } from "@site/src/components/widgets/header"; import { AddingWidget } from "@site/src/components/widgets/adding"; import { WidgetConfig } from "@site/src/components/widgets/configuration"; -import { WidgetInteractionGuide } from "@site/src/components/widgets/interactions"; import { dockerContainersWidget } from "."; -This widget displays the resource usage of your Docker containers and allows you to manage them. Compact mode keeps every configured table column and shows the complete CPU and memory totals whenever the footer is available. +Displays container resource usage and management actions for Docker environments configured through environment +variables. :::info -This widget reads the Docker environments configured through environment variables. You do not need to create a Docker integration under **Management → Integrations**. The widget can only be used with administrator privileges. +This widget does not use an integration from **Management → Integrations** and is restricted to administrators. ::: ### Screenshots @@ -26,7 +26,7 @@ import dockerTable from "./img/table.png"; ### Interactions -Hover a column header to reveal its grab handle, then drag it to reorder the table or drag the header's edge to resize it. The layout is saved automatically for each widget instance and restored after a reload. These controls are disabled while the board is in edit mode. +Column order and width are saved per widget. These controls are unavailable while the board is in edit mode. Each container row has an action menu, accessible via the three-dot icon or by right-clicking the row, with the following options: @@ -35,8 +35,6 @@ Each container row has an action menu, accessible via the three-dot icon or by r - **Remove** - permanently remove the container after a second confirmation click - **Add to Homarr** - create a bookmark app from the container - - ### Adding the widget diff --git a/apps/docs/docs/widgets/downloads/index.mdx b/apps/docs/docs/widgets/downloads/index.mdx index a01051f0c..2296ae0de 100644 --- a/apps/docs/docs/widgets/downloads/index.mdx +++ b/apps/docs/docs/widgets/downloads/index.mdx @@ -1,6 +1,6 @@ --- title: "Download Client" -description: "Allows you to view and manage your Downloads from both Torrent and Usenet clients." +description: "View and manage downloads from Torrent and Usenet clients." hide_title: true --- @@ -18,127 +18,45 @@ import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetHeader } from "@site/src/components/widgets/header"; import { WidgetIntegrations } from "@site/src/components/widgets/integrations"; import { downloadsWidget } from "."; +import advancedView from "./img/advanced-view.png"; +import filterPanel from "./img/filter-panel.png"; -This widget displays torrent, Usenet, and miscellaneous download jobs, along with their progress and other relevant information. It supports 7 download client integrations and provides a rich, responsive table interface. +The Download Client widget combines active jobs from supported Torrent, Usenet, and other download clients. Rows can be +sorted, filtered, expanded, and configured by column. Advanced view adds queue statistics and the complete selected +column set. -### Screenshots +Pause, resume, and delete actions require Interact access to the source integration. `slskd` is list-only. If one source +fails, jobs from healthy integrations remain available. -import downloadsCard from "./img/screenshot.png"; -import contextMenuImg from "./img/context-menu.png"; -import advancedViewImg from "./img/advanced-view.png"; -import filterPanelImg from "./img/filter-panel.png"; +### Advanced view -
- Downloads widget showing torrent and usenet items -
+Downloads advanced view with queue statistics and expanded job details -#### Download-row context menu +### Filtering -
- Downloads row context menu with pause, delete, and copy actions -
+Downloads advanced view filtered by client and state -#### Advanced view - -
- Downloads widget in advanced view with stats, sortable columns, and expanded details -
- -#### Advanced filter panel - -
- Downloads advanced view with the status filter panel open -
- -### Features - -- **Responsive compact table** — in compact mode, selected columns use the established width breakpoints; widget height does not remove configured columns or the footer -- **Sortable columns** — click any sortable column header to sort the current view; the configured default controls the initial column and direction -- **Column customization** — choose which columns to display, then hover a header to reveal its grab handle for reordering or drag its edge to resize it; layouts save automatically per widget -- **Download-row context menu** — copy a download name or ID from any row; pause, resume, and delete actions appear when you have Interact access to that integration -- **Row expansion** — click any row to see full details inline without opening a separate modal -- **Hover tooltips** — hover a download name to see size, speeds, ETA, ratio, and category; open tooltips close when switching between compact and advanced mode -- **Global stats bar** — show queue progress, downloaded/total size, transfer speeds, global torrent ratio, and per-state counts in compact mode; advanced view always includes it -- **Client filtering** — filter downloads by integration or status using the footer filter panel -- **Global controls** — pause/resume actionable queues from the footer bar, limited to selected integrations where you have Interact access -- **Status indicators** — color-coded badges show download state at a glance -- **Speed overview** — total download and upload speeds for the selected clients are displayed in the footer - -:::note - -Compact layouts use their established width breakpoints: below 500px wide, speed columns are hidden; below 300px wide, -the ETA and state columns are hidden too. Height does not remove configured columns or the footer. Advanced view bypasses -the compact width reductions, keeps the selected column set, and always includes the stats bar and footer controls, with -the filter panel available from the footer. - -The filter panel changes the visible rows. Its client/status filters also change the stats bar's progress, size, and -state counts, while transfer-speed totals summarize the selected clients and the global torrent ratio summarizes the -selected torrent clients. The configured category/label filter can optionally be applied to the global torrent ratio -through **Use category filter for global torrent ratio**; footer client/status filters do not change that ratio. - -The per-item **Ratio** is sent bytes divided by the item's total size. **Global Ratio** is total uploaded bytes divided -by total downloaded bytes. - -Mutation controls depend on the integration's Interact permission. Users without that permission can still view rows and -use the row menu's copy actions. `slskd` is list-only: its pause, resume, and delete operations are no-ops, so those -controls have no effect for that client even when Interact permission exposes them. - -The screenshot above is a Downloads row menu, separate from the shared widget context menu. When board right-click menus -are enabled, the shared menu provides widget-level actions such as advanced view, widget options, refresh, and settings. - -::: - -### Supported Integrations +### Supported integrations ### Interactions -- **Right-click** any download to copy its name or ID; pause, resume, and delete are available only with Interact access -- **Click** any row to expand it and see full download details inline -- **Hover** a download name for a quick stats tooltip -- **Stats toggle** — show or hide the global stats bar in compact mode; advanced view always shows the stats bar without - changing the compact choice -- **Pause / Resume** actionable queues using the footer controls -- **Filter** rows by integration or status using the filter button in the footer -- **Sort** by clicking sortable column headers; the default sort is configured per widget, while header changes apply to the current view +- Select a row to expand its details. +- Right-click a row to copy identifiers or run permitted actions. +- Use the footer to filter clients and states, show statistics, or pause and resume actionable queues. diff --git a/apps/docs/docs/widgets/media-missing/index.mdx b/apps/docs/docs/widgets/media-missing/index.mdx index 8ea527d36..4e73bc6e4 100644 --- a/apps/docs/docs/widgets/media-missing/index.mdx +++ b/apps/docs/docs/widgets/media-missing/index.mdx @@ -16,9 +16,8 @@ import { sonarrIntegration } from "@site/docs/integrations/sonarr"; -Monitor which movies and episodes are missing from your library, and track what is currently being downloaded. The widget pulls data from Radarr and Sonarr and groups results by type in two tabs. - -Advanced view always shows both Missing and Queued panels side by side when space allows, requests at least 50 items per source, exposes queue status and time remaining, and keeps partial-integration warnings visible. Compact tab visibility and page-size choices continue to shape the board tile. +The Media Missing & Queue widget shows monitored movies and episodes that are not yet available and items currently in +the Radarr or Sonarr download queue. Advanced view shows both groups with queue status and time remaining. ### Screenshots @@ -52,16 +51,6 @@ import widgetCompact from "./img/compact.png"; | **Missing** | Lists movies (Radarr) and episodes (Sonarr) that are monitored but not yet available in your library. | | **Queued** | Shows items currently being downloaded with a progress bar and estimated time remaining. | -### Sizing - -The widget adapts to its container size, so it looks good at any grid size: - -- **Wide** — fits as many columns of cards as the width allows, filling larger widgets instead of stretching a single column. -- **Short** — packs items into more, tighter columns so they stay visible in the limited height. -- **Narrow (1×N)** — tab labels collapse to counts only and posters scale down. - -Each item shows its poster art (with the artwork bleeding softly behind the card), a type badge, and — on the queue — an animated progress bar with the estimated time remaining. - ### Adding the widget diff --git a/apps/docs/docs/widgets/media-releases/index.mdx b/apps/docs/docs/widgets/media-releases/index.mdx index fea6f8a71..72e6cd3b1 100644 --- a/apps/docs/docs/widgets/media-releases/index.mdx +++ b/apps/docs/docs/widgets/media-releases/index.mdx @@ -17,11 +17,8 @@ import { plexIntegration } from "@site/docs/integrations/plex"; -Provides a list of newly added media or upcoming releases from your media server. Compact rows retain their poster, full release date and time, and configured metadata. - -Releases retain the name and icon of the integration that supplied them. If one integration is unavailable, releases from healthy integrations remain visible and a warning identifies the failed source without exposing connection details. The widget reports an error only when every selected integration fails. - -Advanced view displays every release in a roomy poster layout with its complete available metadata, description, tags, and visible source name, regardless of the compact layout and visibility options. +The Media releases widget shows newly added media or upcoming releases with their source, date, artwork, and configured +metadata. Advanced view adds descriptions and tags. Healthy integrations remain visible when another source fails. ### Screenshots diff --git a/apps/docs/docs/widgets/media-server/img/advanced-view.png b/apps/docs/docs/widgets/media-server/img/advanced-view.png deleted file mode 100644 index 75a49a3a2..000000000 Binary files a/apps/docs/docs/widgets/media-server/img/advanced-view.png and /dev/null differ diff --git a/apps/docs/docs/widgets/media-server/index.mdx b/apps/docs/docs/widgets/media-server/index.mdx index c881bc3c5..66ad8a706 100644 --- a/apps/docs/docs/widgets/media-server/index.mdx +++ b/apps/docs/docs/widgets/media-server/index.mdx @@ -1,6 +1,6 @@ --- title: "Media server streams" -description: "Show the current streams on your media servers" +description: "Show active sessions on media servers." hide_title: true --- @@ -10,9 +10,6 @@ import { WidgetHeader } from "@site/src/components/widgets/header"; import { AddingWidget } from "@site/src/components/widgets/adding"; import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetIntegrations } from "@site/src/components/widgets/integrations"; -import { IconAd } from "@tabler/icons-react"; -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; import { mediaServerWidget } from "."; import { embyIntegration } from "@site/docs/integrations/emby"; import { jellyfinIntegration } from "@site/docs/integrations/jellyfin"; @@ -21,43 +18,24 @@ import { plexIntegration } from "@site/docs/integrations/plex"; -The media server widget shows active sessions across your media servers. -It shows playback progress, pause state, time remaining, the streaming resolution (e.g. `1080p`), and whether each session is direct play, direct stream, or transcoding audio or video. Location and bitrate can be toggled independently. Compact mode keeps the user, currently playing, and status columns together with the stream summary and integration names. +The Media server streams widget combines active sessions from selected servers. It shows playback progress, resolution, +bitrate, location, and direct-play or transcoding state according to the widget configuration. Advanced view adds search, +sorting, and session metadata. -Select a session to inspect its media metadata in an anchored popover. Advanced mode adds search, sorting, location, bitrate, and a summary of playing and transcoding sessions while keeping separate integration instances identifiable. Compact visibility switches do not hide location or bitrate from the complete advanced session view. -If one selected server is unavailable, a warning indicator identifies the degraded result while sessions from healthy servers remain usable. -Sessions without user metadata remain visible and are labeled as an unknown user. +Healthy integrations remain available when another source fails. Navidrome and Plex return currently playing sessions +rather than every connected session. -### Screenshots - -import mediaTable from "./img/table.png"; -import mediaAdvancedView from "./img/advanced-view.png"; - -
- Media server compact streams table - Media server advanced view with stream summary -
- -### Supported Integrations +### Supported integrations + ### Adding the widget diff --git a/apps/docs/docs/widgets/network-controller-status/index.mdx b/apps/docs/docs/widgets/network-controller-status/index.mdx index a9cbfc87c..0a5f234d1 100644 --- a/apps/docs/docs/widgets/network-controller-status/index.mdx +++ b/apps/docs/docs/widgets/network-controller-status/index.mdx @@ -11,16 +11,12 @@ import { AddingWidget } from "@site/src/components/widgets/adding"; import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetHeader } from "@site/src/components/widgets/header"; import { WidgetIntegrations } from "@site/src/components/widgets/integrations"; -import { IconAd } from "@tabler/icons-react"; -import TabItem from "@theme/TabItem"; -import Tabs from "@theme/Tabs"; import { networkControllerStatusWidget } from "."; -Shows connected users and connected guest devices on wired or wireless networks. - -Compact view aggregates the configured controllers into one familiar card for the selected Wi-Fi or wired total. A failed refresh is shown as a small warning instead of replacing the totals card. Advanced view shows both totals separately for every controller, preserving each integration's name, type, and exact update time while keeping partial-source and stale-data warnings visible. +The Network Status widget shows connected users and guests on wired or wireless networks. Advanced view separates totals +by controller. Healthy controllers remain visible when another source fails. ### Screenshots diff --git a/apps/docs/docs/widgets/network-controller-summary/index.mdx b/apps/docs/docs/widgets/network-controller-summary/index.mdx index f90189e5e..1790ec5bd 100644 --- a/apps/docs/docs/widgets/network-controller-summary/index.mdx +++ b/apps/docs/docs/widgets/network-controller-summary/index.mdx @@ -8,17 +8,14 @@ import { WidgetInteractionGuide } from "@site/src/components/widgets/interaction import { unifiControllerIntegration } from "@site/docs/integrations/unifi-controller"; import { AddingWidget } from "@site/src/components/widgets/adding"; -import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetHeader } from "@site/src/components/widgets/header"; import { WidgetIntegrations } from "@site/src/components/widgets/integrations"; -import { IconAd } from "@tabler/icons-react"; -import TabItem from "@theme/TabItem"; -import Tabs from "@theme/Tabs"; import { networkControllerSummaryWidget } from "."; -Shows whether your WAN, internet, Wi-Fi, and VPN are available. The compact board view keeps the familiar status list, including internet latency and the connected VPN-user count. +The Network Controller Summary widget shows WAN, internet, Wi-Fi, and VPN status, including latency and connected-user +counts. ### Screenshots @@ -36,7 +33,7 @@ import summaryCard from "./img/summary.png"; ]} /> -In advanced view, each controller gets its own information matrix showing source, last update, WAN and web status, latency, ping, web uptime, separate Wi-Fi and LAN user and guest counts, and connected VPN users. +Advanced view separates status and user counts by controller. diff --git a/apps/docs/docs/widgets/notebook/img/notebook-enter-editing.webp b/apps/docs/docs/widgets/notebook/img/notebook-enter-editing.webp deleted file mode 100644 index 48ebcd193..000000000 Binary files a/apps/docs/docs/widgets/notebook/img/notebook-enter-editing.webp and /dev/null differ diff --git a/apps/docs/docs/widgets/notebook/img/notebook-exit-editing.webp b/apps/docs/docs/widgets/notebook/img/notebook-exit-editing.webp deleted file mode 100644 index 850e3880a..000000000 Binary files a/apps/docs/docs/widgets/notebook/img/notebook-exit-editing.webp and /dev/null differ diff --git a/apps/docs/docs/widgets/notebook/img/notebook-image-modal.webp b/apps/docs/docs/widgets/notebook/img/notebook-image-modal.webp deleted file mode 100644 index 0d9bab54d..000000000 Binary files a/apps/docs/docs/widgets/notebook/img/notebook-image-modal.webp and /dev/null differ diff --git a/apps/docs/docs/widgets/notebook/img/notebook-link-modal.webp b/apps/docs/docs/widgets/notebook/img/notebook-link-modal.webp deleted file mode 100644 index 5cd3deb58..000000000 Binary files a/apps/docs/docs/widgets/notebook/img/notebook-link-modal.webp and /dev/null differ diff --git a/apps/docs/docs/widgets/notebook/img/notebook-table-modal.webp b/apps/docs/docs/widgets/notebook/img/notebook-table-modal.webp deleted file mode 100644 index 042f5edb1..000000000 Binary files a/apps/docs/docs/widgets/notebook/img/notebook-table-modal.webp and /dev/null differ diff --git a/apps/docs/docs/widgets/notebook/img/notebook-toolbar-lists.webp b/apps/docs/docs/widgets/notebook/img/notebook-toolbar-lists.webp deleted file mode 100644 index 9f3782aa2..000000000 Binary files a/apps/docs/docs/widgets/notebook/img/notebook-toolbar-lists.webp and /dev/null differ diff --git a/apps/docs/docs/widgets/notebook/img/notebook-toolbar-table.webp b/apps/docs/docs/widgets/notebook/img/notebook-toolbar-table.webp deleted file mode 100644 index 656fa80bb..000000000 Binary files a/apps/docs/docs/widgets/notebook/img/notebook-toolbar-table.webp and /dev/null differ diff --git a/apps/docs/docs/widgets/notebook/img/notebook-toolbar.webp b/apps/docs/docs/widgets/notebook/img/notebook-toolbar.webp deleted file mode 100644 index b85224ba0..000000000 Binary files a/apps/docs/docs/widgets/notebook/img/notebook-toolbar.webp and /dev/null differ diff --git a/apps/docs/docs/widgets/notebook/index.mdx b/apps/docs/docs/widgets/notebook/index.mdx index 887908372..bad49b7d0 100644 --- a/apps/docs/docs/widgets/notebook/index.mdx +++ b/apps/docs/docs/widgets/notebook/index.mdx @@ -1,32 +1,31 @@ --- title: "Notebook" -description: "A simple notebook widget that supports markdown." +description: "Rich text notes on a board." hide_title: true --- -import { WidgetInteractionGuide } from "@site/src/components/widgets/interactions"; - import { AddingWidget } from "@site/src/components/widgets/adding"; import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetHeader } from "@site/src/components/widgets/header"; import { notebookWidget } from "."; +import normalView from "./img/normal.png"; +import editView from "./img/edit.png"; -The notebook widget focuses on usability and is designed to be as simple as possible to bring a familiar editing experience to regular users. -It is based on Tiptap.dev and supports most of its features. +The Notebook widget stores rich text on a board. Its editor supports headings, formatting, lists, links, images, tables, +text direction, and alignment. -### Screenshots +Select the edit action or double-click the document to edit it. Save or cancel from the same action area. Editing follows +the board's permissions. -import editOff from "./img/normal.png"; -import editOn from "./img/edit.png"; +### View mode -
- notebook edit-off - notebook edit-on -
+Notebook widget showing a saved note - +### Editing + +Notebook editor with its formatting toolbar ### Adding the widget @@ -35,127 +34,3 @@ import editOn from "./img/edit.png"; ### Configuration - -### Editing - -When your permissions allow it, hover the widget, focus within it, or use a touch device to reveal the edit button in the top right. You can also double-click the document to edit it directly. - -![](./img/notebook-enter-editing.webp) - -You can then decide to save your changes or cancel them to exit editing, using the buttons placed in the same location. - -![](./img/notebook-exit-editing.webp) - -### Notebook toolbar functions - -The notebook offers a variety of functions to edit the text and more. - -![](./img/notebook-toolbar.webp) - -#### Common text formatting - -| Function | Description | -| ---------------------- | ------------------------------------------------------------------- | -| Bold | Makes the selected text bold | -| Italic | Tilts the selected text | -| Strikethrough | Puts a bar through the selected text | -| Color text | Changes the color of the text | -| Colored highlight text | Highlights the text with a chosen color | -| Code | Elevates the text to a box | -| Clear formatting | Erases any of the preceding function's effects on the selected text | - -#### Heading - -Choose a heading size for the line, making the text bigger. Working like titles and sub-titles. - -#### Text Alignment - -Select the alignment on the line. Left, center or right. - -#### Text direction - -Set the current paragraph or heading to left-to-right or right-to-left. This is useful when writing right-to-left text while Homarr is using a left-to-right language, or vice versa. - -#### Misc functions - -##### Blockquote - -Puts the current line in a quoting block. - -##### Horizontal line - -Adds a line that goes from the far right to the far left as a separator. - -#### Lists - -##### Bullet lists - -Simple list with a dot preceding each element. - -##### Ordered lists - -List with numbers preceding each element. - -##### Check lists - -List with a checkbox on each element. - -##### Indentation changes - -![](./img/notebook-toolbar-lists.webp) - -When you are currently in a list of any sort, the last 2 buttons will appear and will allow you to change the indentation of the current list item. - -#### Insert functions - -##### Link controls - -The first buttons is to insert a link, or edit an existing link. The link will be applied on the selected text. - -Pasting a link directly into the text will automatically put the link anchor on it too. - -The second button will remove the link while leaving the text intact. - -![](./img/notebook-link-modal.webp) - -This is the modal for the link, The little button in the textbox can be clicked to make the link open in a new tab. - -##### Image controls - -![](./img/notebook-image-modal.webp) - -##### Source - -You can use a normal link to an image or you can also use locally stored images. - -##### Width - -The aspect ratio will always be respected, so only the width field is necessary. -You can provide a value in a plain number or you can also use percents to have your image size dynamically change on different screens. - -#### Table - -This last control allows you to add a table, for which you can determine the number of columns and row before inserting it. - -![](./img/notebook-table-modal.webp) - -Clicking that button while in a table will delete it. - -##### Table controls - -![](./img/notebook-toolbar-table.webp) - -While in a table, further controls will appear to help edit the table. - -The first one will color the background of the selected cells. - -The second will merge selected cells. - -All the following ones are for editing the wize of the table: - -- Add column on the right -- Add column on the left -- Delete Column -- Add row on top -- Add row below -- Delete Row diff --git a/apps/docs/docs/widgets/notifications/img/notifications.png b/apps/docs/docs/widgets/notifications/img/notifications.png deleted file mode 100644 index 11809be55..000000000 Binary files a/apps/docs/docs/widgets/notifications/img/notifications.png and /dev/null differ diff --git a/apps/docs/docs/widgets/notifications/index.mdx b/apps/docs/docs/widgets/notifications/index.mdx index f68e1baee..210ed303f 100644 --- a/apps/docs/docs/widgets/notifications/index.mdx +++ b/apps/docs/docs/widgets/notifications/index.mdx @@ -4,15 +4,10 @@ description: "Display notification history from an integration" hide_title: true --- -import { WidgetInteractionGuide } from "@site/src/components/widgets/interactions"; - import { WidgetHeader } from "@site/src/components/widgets/header"; import { AddingWidget } from "@site/src/components/widgets/adding"; import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetIntegrations } from "@site/src/components/widgets/integrations"; -import { IconAd } from "@tabler/icons-react"; -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; import { notificationsWidget } from "."; import { ntfyIntegration } from "@site/docs/integrations/ntfy"; import { nextcloudIntegration } from "@site/docs/integrations/nextcloud"; @@ -20,13 +15,8 @@ import { gotifyIntegration } from "@site/docs/integrations/gotify"; -The notifications widget allows you to display notifications from various integrations in a unified view. Compact mode presents them as a vertical list of padded notification cards. - -### Screenshots - -import notificationsScreenshot from "./img/notifications.png"; - -notifications +Displays notification history from the configured integration. Advanced view shows full message bodies, sources, and +available service icons. ### Supported Integrations @@ -34,10 +24,6 @@ import notificationsScreenshot from "./img/notifications.png"; items={[{ integration: ntfyIntegration }, { integration: nextcloudIntegration }, { integration: gotifyIntegration }]} /> -Advanced view always shows available notification logos and sources and removes the compact body line limit. External notification links retain the same safe new-tab behavior. - - - ### Adding the widget diff --git a/apps/docs/docs/widgets/patchmon/index.mdx b/apps/docs/docs/widgets/patchmon/index.mdx index 2175a3945..66a53e9c0 100644 --- a/apps/docs/docs/widgets/patchmon/index.mdx +++ b/apps/docs/docs/widgets/patchmon/index.mdx @@ -1,6 +1,6 @@ --- title: "PatchMon" -description: "Displays host patch statistics from PatchMon including update and security counts." +description: "Displays host patch and security update statistics from PatchMon." hide_title: true --- @@ -15,77 +15,17 @@ import { patchmonIntegration } from "@site/docs/integrations/patchmon"; -This widget displays patch statistics from your PatchMon instance, including total hosts, hosts needing updates, and security update counts. Each stat is shown with a dedicated icon and severity-tinted card background for quick visual scanning. +The PatchMon widget shows host compliance, available updates, security updates, outdated packages, and optional operating +system distribution. Thresholds can use counts or percentages. Advanced view shows the complete posture summary. -PatchMon does not render a built-in widget title. To add a label on your board, open **Edit item → Advanced options → Title** — the same optional overlay badge used by other Homarr widgets. +## Authentication -### Authentication +PatchMon data requires a signed-in Homarr session, including on public boards. Visibility options change presentation, +not the integration response available to an authorized user. -:::note -This widget requires a **signed-in Homarr session**. Anonymous visitors cannot load PatchMon data, even when the board is [public](/docs/management/boards#access-control). Placing this widget on a public board does not expose patch or security statistics to guests. +### Supported integration -Stat visibility toggles in the widget settings control **display only**. Authenticated users with integration query access still receive the full API payload regardless of which stats are hidden in the UI. -::: - -### Compliance hero - -When **Show compliance hero** is enabled (default), the widget displays a ring showing the percentage of hosts that are fully up to date. The ring color follows the same threshold rules as the "Up-to-Date Hosts" stat. When the widget is **2 or more columns wide**, the hero also shows the "Patch Compliance" label and exact host count (e.g. "27 / 42") beside the ring. - -In **1-column-wide** layouts (such as 1×1), the compliance hero switches to a ring-only view so useful compliance data remains visible in tight spaces. If the compliance hero is disabled, compact widgets fall back to the next selected content: OS distribution when enabled, then the first enabled stat. - -### Threshold colors - -When **Enable threshold colors** is on (default), stat values and card backgrounds are colored for at-a-glance severity: - -| Stat | Green | Yellow | Red | -| --------------------------- | ------------- | ------ | --------- | -| Needs Updates | 0 | 1–4 | 5+ | -| Security Updates | 0 | 1–9 | 10+ | -| Hosts with Security Updates | 0 | — | 1+ | -| Up-to-Date Hosts | 100% of total | 90–99% | below 90% | -| Outdated Packages | 0 | 1–49 | 50+ | - -Enable **Advanced thresholds** to override warning and critical values per stat, using either absolute counts or percentages of total hosts. - -### OS distribution - -When **Show OS distribution** is enabled, the widget shows a breakdown of monitored hosts by operating system. Two display modes are available: - -- **Horizontal bars** (default) — a scrollable list of colored progress bars showing each OS's share -- **Donut chart** — a compact donut chart visualization that scales down in narrow layouts - -The OS distribution limit defaults to **All**. A widget size of **2×3** or larger is recommended when using this section alongside the default stats, but compact 1×1 and 2×1 layouts can still show multiple OS rows when OS distribution is the primary selected content. Wider donut layouts can also show a compact legend beside the chart. - -### Responsive sizing - -The widget adapts its layout based on the available space: - -| Widget size | Layout | -| ----------------- | ------------------------------------------------------------------------------------------------------------------- | -| **1×1** | Primary selected content: compliance ring (no label), compact OS distribution, or up to two enabled stats | -| **2×1** / **1×2** | Compact primary content; **2×1** shows compliance label and host ratio beside the ring; **1×2** uses ring-only hero | -| **2×2** (default) | Compliance hero, stat grid with icons, and tinted cards | -| **2×3** / **3×2** | Hero, stats, OS distribution, and "last updated" footer | -| **3×3** or larger | Full layout with up to 4-column stat grid, donut chart, and optional OS legend | - -### Last updated - -When the widget has enough space, a "last updated" timestamp appears at the bottom showing how recently PatchMon refreshed its data. Narrow layouts use a shortened timestamp such as `5m ago`; wider short layouts can show the full translated text. - -### Advanced view - -Advanced view is a complete PatchMon posture view. It always shows the compliance hero, all eight host and package statistics, the full OS distribution with versions, and the last-updated time. Compact visibility switches and OS limits still shape the board tile, but do not hide already-fetched security information in advanced view. Threshold and chart-style choices remain in effect. - -### Supported Integrations - - + diff --git a/apps/docs/docs/widgets/smart-home-entity-state/index.mdx b/apps/docs/docs/widgets/smart-home-entity-state/index.mdx index acf6e4e8d..b3067848b 100644 --- a/apps/docs/docs/widgets/smart-home-entity-state/index.mdx +++ b/apps/docs/docs/widgets/smart-home-entity-state/index.mdx @@ -10,19 +10,13 @@ import { WidgetHeader } from "@site/src/components/widgets/header"; import { AddingWidget } from "@site/src/components/widgets/adding"; import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetIntegrations } from "@site/src/components/widgets/integrations"; -import { IconAd } from "@tabler/icons-react"; -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; import { smartHomeEntityStateWidget } from "."; import { homeAssistantIntegration } from "@site/docs/integrations/home-assistant"; -The entity state enables you to display the current state of an entity. Compact mode presents the friendly name first and its state beneath it. -This works with most entities and enables you display almost any data. -It is recommended that you transform data on the integration as much as possible since Homarr's capabilities in transformation are very limited. - -Advanced view shows the safe Home Assistant metadata owned by Homarr: the friendly name, entity ID, unit, device class, icon, last-changed time, and last-updated time. Arbitrary attributes remain intentionally excluded. +The Entity State widget shows a Home Assistant entity's state and can optionally toggle it. Advanced view includes the +entity ID, unit, device class, icon, and update timestamps; arbitrary attributes are not exposed. ### Screenshots @@ -59,18 +53,10 @@ import temperature from "./img/temperature.png"; -### How to find the entity ID +### Entity ID -To find the entity ID in Home Assistant, follow these steps: - -1. Open Home Assistant and go to the **Developer Tools** section (usually found in the sidebar). -2. Click on the **States** tab. -3. In the list of entities, find the entity you want to use. -4. The entity ID will be displayed in the format `domain.object_id` (e.g., `light.living_room_light`). -5. Copy the entity ID and paste it into the widget configuration in Homarr. It will then show the State that is visible in Home Assistant. +Find the entity under **Home Assistant → Developer Tools → States** and copy its `domain.object_id` value. import retrieveEntityId from "./img/retrieve-entity-id.png"; -
- homeassistant retrieve-entity-id -
+Home Assistant entity IDs under Developer Tools and States diff --git a/apps/docs/docs/widgets/smart-home-execute-automation/index.mdx b/apps/docs/docs/widgets/smart-home-execute-automation/index.mdx index 249c85fa0..7634298a2 100644 --- a/apps/docs/docs/widgets/smart-home-execute-automation/index.mdx +++ b/apps/docs/docs/widgets/smart-home-execute-automation/index.mdx @@ -10,17 +10,13 @@ import { WidgetHeader } from "@site/src/components/widgets/header"; import { AddingWidget } from "@site/src/components/widgets/adding"; import { WidgetConfig } from "@site/src/components/widgets/configuration"; import { WidgetIntegrations } from "@site/src/components/widgets/integrations"; -import { IconAd } from "@tabler/icons-react"; -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; import { smartHomeExecuteAutomationWidget } from "."; import { homeAssistantIntegration } from "@site/docs/integrations/home-assistant"; -The execute automation widget allows you to trigger an automation with one click. - -Advanced view shows the automation ID, interaction permission, last successful run in the current browser session, and the latest action error together. Session-only history is not presented as Home Assistant history. +The Execute Automation widget triggers a Home Assistant automation. Advanced view shows the automation ID, permission, +latest error, and last successful run in the current browser session. ### Screenshots @@ -47,10 +43,6 @@ import withDisplayname from "./img/with-displayname.png"; ]} /> -### Interactions - -- Trigger the automation by clicking on the widget. - ### Adding the widget diff --git a/apps/docs/docs/widgets/timer/index.mdx b/apps/docs/docs/widgets/timer/index.mdx index 49e208c90..16071bff0 100644 --- a/apps/docs/docs/widgets/timer/index.mdx +++ b/apps/docs/docs/widgets/timer/index.mdx @@ -13,20 +13,11 @@ import { timerWidget } from "."; -The Timer / Pomodoro widget runs in your browser and does not require an integration. A running timer uses a saved -deadline, so reopening the board or returning from a background tab restores the correct remaining time. +The Timer / Pomodoro widget runs in the browser without an integration. Timer mode uses one duration; Pomodoro mode +alternates configurable focus, short-break, and long-break phases. -Timer mode uses one configured duration. Pomodoro mode starts with a focus session, follows most completed focus -sessions with a short break, and uses a long break after the configured number of focus sessions. Automatic break and -focus starts are separate options and are disabled by default. When automatic starts are enabled, elapsed phases are -reconciled from their original deadlines after the board returns to the foreground. - -Advanced view shows the sequence, durations, and local alert preferences. Sounds are enabled by default, while browser -notifications are requested only after you enable them. Progress and alert preferences are stored per board and widget -in the current browser; clearing site data resets them, and widget previews do not persist timer state. - -Alerts can fire while Homarr is open, but browser or operating-system settings may suppress notifications. Reduced-motion -and forced-colors preferences replace the animated completion effect with a static border. +Progress and alert preferences are stored per board and widget in the current browser. Notifications can fire only +while Homarr is open. diff --git a/apps/docs/docs/widgets/tracearr/index.mdx b/apps/docs/docs/widgets/tracearr/index.mdx index 4ddb47acf..e4ba9b2d9 100644 --- a/apps/docs/docs/widgets/tracearr/index.mdx +++ b/apps/docs/docs/widgets/tracearr/index.mdx @@ -15,9 +15,8 @@ import { tracearrIntegration } from "@site/docs/integrations/tracearr"; -The Tracearr widget provides a real-time monitoring dashboard for your media server activity. It displays active streams, user statistics, recent watching history, and policy violations. Compact mode renders every enabled section in that familiar order without hiding or truncating sections based on widget height. - -When multiple Tracearr integrations are selected, every stream, violation, and activity row keeps its source identity and an integration-scoped key. Data from healthy sources remains visible if another source fails, and a warning identifies each unavailable integration without exposing private request details. If every selected integration fails, the widget reports an error; if cached data remains visible after a later total failure, a stale-data warning is shown. +The Tracearr widget shows active streams, user statistics, recent activity, and policy violations. Rows identify their +source integration, and healthy sources remain visible when another source fails. ### Sections @@ -28,16 +27,6 @@ When multiple Tracearr integrations are selected, every stream, violation, and a | **Recent Activity** | A paginated list of watching history with user avatars and watched status. | | **Violations** | Alerts for policy violations (e.g., concurrent stream limits) with severity levels. | -### Screenshots - -import widgetOverview from "./img/widget-overview.png"; -import streamsAndStats from "./img/streams-and-stats.png"; - -
- tracearr-widget-overview - tracearr-streams-and-stats -
- ### Adding the widget diff --git a/apps/docs/docs/widgets/ups/index.mdx b/apps/docs/docs/widgets/ups/index.mdx index cba3c5238..d4c32b785 100644 --- a/apps/docs/docs/widgets/ups/index.mdx +++ b/apps/docs/docs/widgets/ups/index.mdx @@ -15,27 +15,8 @@ import { peaNutIntegration } from "@site/docs/integrations/peanut"; -This widget displays the status of the UPS devices reported by a Network UPS Tools (NUT) server. Each device shows its -status (online, on battery, charging or low battery), battery charge and estimated runtime, output load, and input and -output voltage. - -Every device keeps an integration-scoped identity. Advanced view always labels each device with its owning integration, while compact layouts add the source label only when multiple healthy integrations are present. - -When multiple UPS integrations are selected, devices from healthy sources remain visible if another source fails. A warning indicator identifies each unavailable integration without exposing private request details. If every selected integration fails, the widget reports an error; if cached data remains visible after a later total failure, a stale-data warning is shown. - -### Layouts - -import screenshotFull from "./img/screenshot.png"; -import screenshotCompact from "./img/screenshot-compact.png"; -import screenshotMini from "./img/screenshot-mini.png"; - -The widget adapts to the size of the tile, so it stays readable from a full dashboard panel down to a single cell. Multiple UPS devices scroll within the widget at any height. - -| Layout | Size | Preview | -| ------- | --------------- | --------------------------------------------------------------------------- | -| Full | 3+ columns wide | UPS widget full layout | -| Compact | ~2 columns | UPS widget compact layout | -| Mini | 1 column | UPS widget mini layout | +The UPS widget shows NUT device state, battery charge, runtime, load, and voltage. Advanced view identifies each source +integration. Devices from healthy integrations remain visible when another source fails. ### Supported Integrations diff --git a/apps/docs/docs/widgets/weather/img/advanced-view.png b/apps/docs/docs/widgets/weather/img/advanced-view.png deleted file mode 100644 index 96e37daf4..000000000 Binary files a/apps/docs/docs/widgets/weather/img/advanced-view.png and /dev/null differ diff --git a/apps/docs/docs/widgets/weather/index.mdx b/apps/docs/docs/widgets/weather/index.mdx index c03357f87..931cb87b6 100644 --- a/apps/docs/docs/widgets/weather/index.mdx +++ b/apps/docs/docs/widgets/weather/index.mdx @@ -1,6 +1,6 @@ --- title: "Weather" -description: "Displays the current weather information of a set location." +description: "Displays current weather and a forecast for a location." hide_title: true --- @@ -13,21 +13,8 @@ import { weatherWidget } from "."; -The Weather Widget displays current conditions and a responsive forecast for a selected location. New widgets start -with the city and a three-day forecast visible. As the widget gets smaller, it keeps the current condition and -temperature readable before removing secondary details or forecast days. - -Select a forecast day to inspect precipitation, apparent temperature, humidity, wind, UV index, sunrise, sunset and -daylight duration with a mouse, keyboard or touch. Open the advanced view for a current-condition summary, a 24-hour -temperature and precipitation chart, and the complete seven-day forecast. The chart has an equivalent data table for -assistive technologies. - -The **Show humidity** option controls humidity across the compact current-conditions view, advanced summary, hourly -details, and daily forecast details. Forecast cards use a roomier adaptive grid in advanced view, with four columns on -the standard desktop surface and fewer columns as the surface narrows. - -Weather icons are static by default. Animation can be enabled in the widget configuration, but the operating system's -reduced-motion preference always disables it. +The Weather widget shows current conditions and a responsive forecast. Select a forecast day for details; advanced view +adds hourly temperature and precipitation charts and the complete seven-day forecast. @@ -41,10 +28,8 @@ reduced-motion preference always disables it. ### Data source -We use the Open Meteo API to fetch the weather and locations. Active weather data refreshes every ten minutes, while -identical location requests can reuse a server response for five minutes. A manual refresh may therefore return the -same still-current server response. If a refresh fails, Homarr keeps the last successful data visible and shows an -error indicator. +Weather and location data come from Open-Meteo. Active weather refreshes every ten minutes; identical location requests +can reuse a server response for five minutes. Failed refreshes keep the last successful data with an error indicator. -Set `NO_EXTERNAL_CONNECTION=true` to disable this and other internet-backed requests. -If you need to whitelist the api, please use the following URL: `https://open-meteo.com` +Set `NO_EXTERNAL_CONNECTION=true` to disable this and other internet-backed requests. Allowlist +`https://open-meteo.com` when outbound access is restricted. diff --git a/apps/docs/docs/workshop/development.mdx b/apps/docs/docs/workshop/development.mdx deleted file mode 100644 index a7622cbc3..000000000 --- a/apps/docs/docs/workshop/development.mdx +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: Workshop development -sidebar_position: 4 -tags: - - Workshop - - Developer - - Docusaurus - - PocketBase ---- - -# Workshop development - -Install the repository dependencies and make sure Docker is available before starting the Workshop services. See the -[main development guide](../advanced/development/getting-started) for the repository prerequisites. - -## Run PocketBase and documentation - -Start PocketBase in one terminal: - -```sh -cp apps/workshop/.env.example apps/workshop/.env -docker compose --env-file apps/workshop/.env -f apps/workshop/docker-compose.yml up --build workshop -``` - -Then start Docusaurus in another terminal: - -```sh -WORKSHOP_API_URL=http://127.0.0.1:8090 pnpm dev:docs -``` - -PocketBase runs on port 8090 and Docusaurus on port 3003. Stopping the services preserves the PocketBase volume. - -Open `http://127.0.0.1:8090/_/` and create the first PocketBase superuser. The Workshop UI is available at -`http://127.0.0.1:3003/workshop`. - -Point Homarr at the local services with: - -```dotenv -HOMARR_WEBSITE_URL=http://127.0.0.1:3003 -WORKSHOP_API_URL=http://127.0.0.1:8090 -``` - -Restart `pnpm dev:docs` after changing the Docusaurus URL variables. If Homarr is also running, restart its `pnpm dev` -process after changing the Workshop URLs. GitHub OAuth is optional locally. See -[`apps/workshop/README.md`](https://github.com/homarr-labs/homarr/blob/HEAD/apps/workshop/README.md) for OAuth, -Workshop moderator promotion, logs, tests, backup, restore, stopping, and intentional volume reset. - -## URL testing - -Docusaurus reads `HOMARR_WEBSITE_URL`, `WORKSHOP_API_URL`, and `WORKSHOP_WEB_URL` when it starts or builds. Homarr uses -`WORKSHOP_WEB_URL` for public Workshop links while API and documentation origins remain independent. These values do -not rely on `NEXT_PUBLIC_*` build variables. Test separate origins before release: - -```sh -HOMARR_WEBSITE_URL=http://127.0.0.1:3003 \ -WORKSHOP_API_URL=http://127.0.0.1:8090 \ -WORKSHOP_WEB_URL=http://127.0.0.1:3003/workshop \ -pnpm dev:docs -``` - -The [Workshop operator guide](./operator) covers production environment variables, staging, and service validation. diff --git a/apps/docs/docs/workshop/homarr-provider.mdx b/apps/docs/docs/workshop/homarr-provider.mdx index aa0ae7058..53c34f0e4 100644 --- a/apps/docs/docs/workshop/homarr-provider.mdx +++ b/apps/docs/docs/workshop/homarr-provider.mdx @@ -8,46 +8,31 @@ tags: - Community --- -import { OpenCollectiveLink } from "@site/src/components/assistant-provider/open-collective-link"; +import { HomarrProviderDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams"; # Homarr provider -The Homarr provider gives Community Workshop users access to the **Homarr model** without an administrator API key. -The Homarr team chooses the upstream model based on quality, reliability, and cost. +The Homarr provider gives Community Workshop users access to a server-selected model without configuring an Assistant +API key. -## Set it up +Select **Homarr** under **Management → Assistant**, enable Assistant, then sign in to the Workshop when prompted. -1. Open **Management → Assistant**. -2. Select **Homarr** as the provider. -3. Save the provider connection. -4. Select the available model, enable the assistant, and save. -5. Open the assistant and sign in to the Workshop when asked. + -## Daily allowance +## Allowance -- Each user gets **50 request units per UTC day**. -- Each model request uses one unit. A tool loop can use several units. -- Forwarded requests count even if the model later fails. -- Allowances reset at 00:00 UTC. A shared daily limit also applies. +- Each user receives 50 request units per UTC day. +- Each model request consumes one unit; a tool loop can consume several. +- Forwarded requests count even when the upstream model fails. +- A shared daily service limit also applies. -The battery beside the model selector shows the remaining allowance and reset time. Workshop enforces all limits on -its server; changing the browser clock cannot bypass them. +Assistant shows the remaining allowance and reset time beside the model control. -## Privacy +## Data handling -Workshop keeps the OpenRouter API key on its server. Homarr and the browser never receive it. +Prompts, attachments, tools, and tool results pass through Workshop and OpenRouter. Workshop does not retain request or +response content; it stores the user, UTC day, and counters required for limits. OpenRouter is configured for zero data +retention with data collection disabled. -Prompts, attachments, tools, and tool results pass through Workshop and OpenRouter. Workshop does not retain this -content or the responses. It stores only the user, UTC day, and counters needed to enforce allowances. Each active day -has a separate quota record so Workshop operators can inspect per-user daily usage without seeing request content. -OpenRouter is configured for zero data retention with data collection disabled. Homarr does not use this content to -train models. - -We would rather become millionaires in a more ethical manner. - -The community pays for these requests. Donations help cover the cost. - - - -Workshop operators can change the upstream model, per-user allowance, global allowance, and security limits in the -[Workshop operator guide](./operator#homarr-provider-proxy). +Operators configure the model, limits, and upstream key; see the +[Workshop operator guide](/docs/advanced/development/workshop-operator#homarr-provider). diff --git a/apps/docs/docs/workshop/index.mdx b/apps/docs/docs/workshop/index.mdx index 686866412..1be8b1f48 100644 --- a/apps/docs/docs/workshop/index.mdx +++ b/apps/docs/docs/workshop/index.mdx @@ -7,45 +7,40 @@ tags: - Custom CSS --- +import { WorkshopFlowDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams"; + # Community Workshop -The [Community Workshop](pathname:///workshop) is where Homarr users share Custom Widgets and dashboard CSS. +The [Community Workshop](pathname:///workshop) hosts community Custom Widgets and dashboard CSS. :::warning Experimental -Workshop content is made by the community. Review it before installation and back up your Homarr instance. +Workshop content is community-maintained. Review its source and permissions before installation. ::: -## Find and install content +## Content flow -Browse the Workshop by type, date, popularity, or recent activity. Each submission includes its source, screenshots, -author, revision, comments, and reports. + -Administrators can install content without leaving Homarr: +Workshop also exposes the [Homarr Assistant provider](./homarr-provider). Its model-routing and quota path is separate +from Custom Widget and CSS submissions. -- **Custom Widgets:** open **Management → Custom Widgets**, then select **Import from Workshop**. -- **Custom CSS:** open a board's **Settings → Custom CSS**, then select **Import from Workshop**. +## Install content -Homarr shows the complete source and required permissions before installation. Widget credentials are entered in your -Homarr instance and are never included in a Workshop submission. +- Install a Custom Widget from **Management → Custom Widgets → Import from Workshop**. +- Import dashboard CSS from **Board settings → Custom CSS → Import from Workshop**. -## Share your work +Custom Widget credentials are configured in your Homarr instance and are not part of the Workshop submission. -For a saved Custom Widget, open **Management → Custom Widgets**, use its action menu, and select **Publish to -Workshop**. Review the public listing details and source URLs, then publish the credential-free export. Custom CSS and -manual submissions can be shared directly from the Workshop website with **Share yours**. +## Publish content -Publishing creates the listing immediately. To update or delete it, review reports, or mark it outdated, open the -Workshop website, sign in, and select **Yours**. Editing a submission does not change its Workshop URL. +Publish a saved Custom Widget from its action menu under **Management → Custom Widgets**. Custom CSS and manual +submissions can be published from the Workshop website. -## Voting, comments, and reports +Sign in to the Workshop and open **Yours** to update or delete submissions and review reports. Signed-in users can vote, +comment, and report content; Workshop moderators can remove content. Workshop moderation is separate from administration +of a Homarr instance. -Signed-in users can vote, comment, and report submissions. Authors can edit their own comments and submissions. -Workshop moderators can review reports, remove comments, and delete unsafe content. Reports do not remove a submission -automatically. - -A Workshop moderator manages the public community. This is separate from the administrator role on a Homarr instance. - -Deployment and server configuration are in the [Workshop operator guide](./operator). Local setup is in -[Workshop development](./development). +See the [Workshop operator guide](/docs/advanced/development/workshop-operator) to host Workshop or +[Workshop development](/docs/advanced/development/workshop) to run it from the repository. diff --git a/apps/docs/docs/workshop/operator.mdx b/apps/docs/docs/workshop/operator.mdx deleted file mode 100644 index 7ec1aac7b..000000000 --- a/apps/docs/docs/workshop/operator.mdx +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: Workshop operator guide -sidebar_label: Operator guide -sidebar_position: 3 -tags: - - Workshop - - Deployment - - Environment variables - - PocketBase ---- - -# Workshop operator guide - -Workshop is powered by [PocketBase](https://pocketbase.io). The production image compiles the current Docusaurus site -and serves it together with the API from one origin. The deployment lives in `apps/workshop/` with a Dockerfile, -Compose configuration, version-controlled migrations, hooks, a smoke test, and ACT-local workflow instructions. - -Submission links include Open Graph and X/Twitter metadata for the submission title, description, and type. The first -uploaded screenshot is used as the social preview image; submissions without screenshots use the Homarr logo. - -Run `pnpm docker:workshop` for PocketBase on port 8090, then run -`WORKSHOP_API_URL=http://127.0.0.1:8090 pnpm dev:docs` for Docusaurus on port 3003. `pnpm docker:docs` builds the -combined production layout. Normal start and stop commands retain data; `down --volumes` is an intentional, -irreversible development reset. See [Workshop development](./development) for the complete local setup. - -## Authentication and notifications - -GitHub needs only the central callback `https:///api/oauth2-redirect`. Keep PocketBase origins -unrestricted unless every self-hosted Homarr caller is explicitly listed. Configure both `GITHUB_CLIENT_ID` and -`GITHUB_CLIENT_SECRET`; supplying only one is a startup error. Set `WORKSHOP_PUBLIC_ORIGIN` in production so generated -links and email use the public host. Workshop stores only the OAuth provider username in `users.name`, and users cannot -rename it. Map **OAuth2 username** to `name`; leave OAuth2 id, full name, and avatar mappings empty. Profile and avatar -URLs are derived from `https://github.com/` and `https://github.com/.png`, so PocketBase does not -store duplicate profile metadata or avatar files. Configure SMTP for comment, report, and removal notices. - -## Environment variables - -The public URL contract and Workshop-only server configuration are: - -| Variable | Purpose | Default | -| -------------------------------------- | --------------------------------------------- | ------------------------------ | -| `HOMARR_WEBSITE_URL` | Documentation/site base used by Homarr links | `https://homarr.dev` | -| `WORKSHOP_API_URL` | PocketBase API used by Homarr and docs | `HOMARR_WEBSITE_URL` | -| `WORKSHOP_WEB_URL` | Public Workshop links in Homarr | `HOMARR_WEBSITE_URL/workshop` | -| `WORKSHOP_PUBLIC_ORIGIN` | PocketBase-generated links and email | Required in production | -| `PB_ALLOWED_ORIGINS` | PocketBase browser origins | `*` for the central community | -| `OPENROUTER_API_KEY` | Server-only key for the Homarr provider proxy | Provider disabled when empty | -| `HOMARR_AI_DAILY_REQUEST_LIMIT` | Per-user daily provider allowance | `50` | -| `HOMARR_AI_GLOBAL_DAILY_REQUEST_LIMIT` | Shared daily ceiling across all users | `10000` | -| `HOMARR_AI_OPENROUTER_BASE_URL` | OpenRouter-compatible proxy upstream | `https://openrouter.ai/api/v1` | -| `HOMARR_AI_OPENROUTER_MODEL` | Server-selected upstream model | Selected by the Homarr team | - -All public URL variables reject non-HTTP protocols, embedded credentials, query strings, and fragments, and normalize -trailing slashes when Homarr or Docusaurus starts. The deprecated docs-only `WORKSHOP_URL` alias remains for one -release; `WORKSHOP_API_URL` takes precedence for API calls and `WORKSHOP_WEB_URL` takes precedence for public Workshop -links. The combined Workshop image writes the public URLs into its browser -runtime configuration whenever the container starts; the Docker build arguments remain fallbacks. Restart the -container after changing these values, without rebuilding it. - -### Homarr provider proxy - -The [Homarr provider](./homarr-provider) proxy is part of the Workshop image. `OPENROUTER_API_KEY` enables the proxy, -`HOMARR_AI_OPENROUTER_BASE_URL` selects its OpenRouter-compatible upstream, `HOMARR_AI_OPENROUTER_MODEL` selects the -private upstream model behind the stable `homarr/model` alias, and the two allowance variables provide per-user and -shared request ceilings. Lowering either allowance takes effect for existing users. The upstream URL cannot contain -embedded credentials, a query, or a fragment and must use HTTPS. Tests can explicitly opt into an insecure local mock -with `HOMARR_AI_ALLOW_INSECURE_UPSTREAM=true`; do not use that setting with a real API key. - -The proxy overwrites client routing and generation limits. It requires OpenRouter zero-data-retention routing, denies -data-collecting providers, limits responses to 32,768 completion tokens, and does not retain prompts, responses, or -per-request telemetry. It accepts only uploaded image data, conservatively bounds text to the advertised context, and -allows at most two concurrent requests per user and 100 across the service. Keep an OpenRouter account-level credit -limit as the final monetary backstop because request quotas are not dollar accounting. - -PocketBase stores one `assistant_quotas` record per user and active UTC day. Workshop superusers can use this private -collection for a daily usage breakdown; regular users cannot list or view its records. - -Run `pnpm test:workshop` to test authentication, streaming, UTC reset, atomic per-user and global quota enforcement, -failed-request accounting, identity attribution, server-selected model routing, function tools, input and output -controls, privacy routing, spoofing resistance, absence of request logs, and migration rollback. - -An operator can explicitly smoke-test a deployed Workshop against its real configured upstream with a dedicated, -low-quota test user: - -```sh -HOMARR_AI_LIVE_SMOKE=1 \ -WORKSHOP_LIVE_TEST_URL=https://workshop.example.com \ -WORKSHOP_LIVE_TEST_TOKEN= \ -pnpm test:workshop-live-provider -``` - -This optional check consumes one provider request. The test client needs neither the OpenRouter key nor the private -upstream model ID. Do not run it in CI or with a normal user's Workshop token. - -## Staging and demo deployment - -Use `apps/workshop/docker-compose.staging.yml` with the published `ghcr.io/homarr-labs/workshop:v2` image for a v2 -preview. Copy `apps/workshop/.env.staging.example` to `.env.staging`; its default public contract is: - -```dotenv -HOMARR_WEBSITE_URL=https://v2.preview.homarr.dev -WORKSHOP_API_URL=https://v2.preview.homarr.dev -WORKSHOP_PUBLIC_ORIGIN=https://v2.preview.homarr.dev -PB_ALLOWED_ORIGINS=* -``` - -Start or update it from the repository root: - -```sh -docker compose --env-file apps/workshop/.env.staging \ - -f apps/workshop/docker-compose.staging.yml pull -docker compose --env-file apps/workshop/.env.staging \ - -f apps/workshop/docker-compose.staging.yml up --detach -curl --fail http://127.0.0.1:8090/api/health -``` - -The service binds to `127.0.0.1:8090`. Terminate TLS at a reverse proxy and forward the **entire hostname**, including -`/api`, `/_/`, and `/workshop-runtime-config.js`; forwarding only `/workshop` breaks PocketBase and runtime URL loading. -This combined image serves both the documentation site and PocketBase, so use a dedicated Workshop hostname if the -chosen hostname already serves Homarr itself. In that case, replace the hostname in all three URL values. Homarr -derives the public Workshop page by appending `/workshop` to `HOMARR_WEBSITE_URL`. - -The Compose volume preserves PocketBase data across pulls and container recreation. The mutable `v2` tag is suitable -for previews; use the `sha-` tag for promotion. For the public central Workshop, `PB_ALLOWED_ORIGINS=*` allows -self-hosted Homarr origins to use the API and OAuth. A private demo may use a comma-separated origin allowlist instead. -GitHub OAuth requires both credentials and the callback `https://v2.preview.homarr.dev/api/oauth2-redirect`. Restart -after changing environment values, then verify the health endpoint, `/workshop`, a public listing request, GitHub -sign-in, and an installation from the Homarr preview. - -## Backup and restore - -PocketBase data lives in `/pb_data`. Stop writes and copy it to a new, empty backup directory: - -```sh -docker compose --env-file apps/workshop/.env.staging \ - -f apps/workshop/docker-compose.staging.yml stop workshop -docker compose --env-file apps/workshop/.env.staging \ - -f apps/workshop/docker-compose.staging.yml cp workshop:/pb_data/. ./workshop-backup -docker compose --env-file apps/workshop/.env.staging \ - -f apps/workshop/docker-compose.staging.yml start workshop -``` - -Restore only after preserving the current volume and confirming the backup contains `data.db`: - -```sh -test -f ./workshop-backup/data.db -docker compose --env-file apps/workshop/.env.staging \ - -f apps/workshop/docker-compose.staging.yml stop workshop -docker compose --env-file apps/workshop/.env.staging \ - -f apps/workshop/docker-compose.staging.yml run --rm --no-deps --entrypoint sh workshop \ - -c 'find /pb_data -mindepth 1 -maxdepth 1 -exec rm -rf {} +' -docker compose --env-file apps/workshop/.env.staging \ - -f apps/workshop/docker-compose.staging.yml cp ./workshop-backup/. workshop:/pb_data -docker compose --env-file apps/workshop/.env.staging \ - -f apps/workshop/docker-compose.staging.yml start workshop -curl --fail http://127.0.0.1:8090/api/health -``` - -The restore empties the selected volume. Rehearse it in staging, then verify sign-in and one installation. Publish by -immutable digest, validate that exact digest in staging, and promote the same digest. diff --git a/apps/docs/src/components/assistant-provider/open-collective-link.module.css b/apps/docs/src/components/assistant-provider/open-collective-link.module.css deleted file mode 100644 index 27be276cf..000000000 --- a/apps/docs/src/components/assistant-provider/open-collective-link.module.css +++ /dev/null @@ -1,41 +0,0 @@ -.link { - display: inline-flex; - align-items: center; - gap: 0.5rem; - padding: 0.45rem 0.7rem; - border: 1px solid var(--ifm-color-emphasis-300); - border-radius: 0.5rem; - background: var(--ifm-background-surface-color); - color: var(--ifm-font-color-base); - font-size: 0.875rem; - font-weight: 600; - line-height: 1.25; - text-decoration: none; - transition: - background-color 150ms ease, - border-color 150ms ease; -} - -.link:hover { - border-color: var(--ifm-color-emphasis-500); - background: var(--ifm-color-emphasis-100); - color: var(--ifm-font-color-base); - text-decoration: none; -} - -.link:focus-visible { - outline: 2px solid var(--ifm-color-primary); - outline-offset: 2px; -} - -.logo { - width: 1.1rem; - height: 1.1rem; - flex: 0 0 auto; -} - -@media (prefers-reduced-motion: reduce) { - .link { - transition: none; - } -} diff --git a/apps/docs/src/components/assistant-provider/open-collective-link.tsx b/apps/docs/src/components/assistant-provider/open-collective-link.tsx deleted file mode 100644 index 75499850f..000000000 --- a/apps/docs/src/components/assistant-provider/open-collective-link.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import Translate from "@docusaurus/Translate"; - -import styles from "./open-collective-link.module.css"; - -export const OpenCollectiveLink = () => ( - - - Donate to Homarr on OpenCollective - -); diff --git a/apps/docs/src/components/integrations/adding.tsx b/apps/docs/src/components/integrations/adding.tsx index 9846675ab..e0c94e41c 100644 --- a/apps/docs/src/components/integrations/adding.tsx +++ b/apps/docs/src/components/integrations/adding.tsx @@ -1,8 +1,8 @@ export const AddingIntegration = () => { return (

- You can find how to add the integration on the Integrations Management{" "} - documentation page. + Create the connection under Management → Integrations. See{" "} + Managing integrations.

); }; diff --git a/apps/docs/src/components/pages/core-concepts/technical-diagrams.module.css b/apps/docs/src/components/pages/core-concepts/technical-diagrams.module.css new file mode 100644 index 000000000..10e67a1d5 --- /dev/null +++ b/apps/docs/src/components/pages/core-concepts/technical-diagrams.module.css @@ -0,0 +1,400 @@ +.diagram { + --diagram-ink: var(--ifm-font-color-base); + --diagram-muted: var(--ifm-color-emphasis-700); + --diagram-panel: var(--ifm-background-surface-color); + --diagram-surface: var(--ifm-background-color); + --diagram-line: var(--ifm-color-emphasis-300); + display: grid; + gap: 0.9rem; + margin: 1.25rem 0 1.75rem; + padding: 1rem; + border: 1px solid var(--diagram-line); + border-radius: 0.75rem; + color: var(--diagram-ink); + background: var(--diagram-panel); +} + +.routeBlock { + display: grid; + gap: 0.55rem; +} + +.routeBlock + .routeBlock { + padding-top: 0.85rem; + border-top: 1px solid var(--diagram-line); +} + +.routeHeading { + display: flex; + align-items: center; + gap: 0.4rem; + min-width: 0; +} + +.routeHeading > span { + display: grid; + place-items: center; + color: var(--ifm-color-primary); +} + +.routeHeading strong { + font-size: 0.74rem; +} + +.routeHeading small { + color: var(--diagram-muted); + font-family: var(--font-mono); + font-size: 0.58rem; +} + +.threeStepLane, +.fourStepLane { + display: grid; + align-items: stretch; + gap: 0.35rem; +} + +.threeStepLane { + grid-template-columns: minmax(0, 1fr) 3.25rem minmax(0, 1fr) 3.25rem minmax(0, 1fr); +} + +.fourStepLane { + grid-template-columns: minmax(0, 1fr) 3.1rem minmax(0, 1fr) 3.1rem minmax(0, 1fr) 3.1rem minmax(0, 1fr); +} + +.node { + display: grid; + align-content: start; + gap: 0.65rem; + min-width: 0; + min-height: 6.25rem; + padding: 0.7rem; + border: 1px solid var(--diagram-line); + border-radius: 0.55rem; + color: var(--diagram-ink); + background: var(--diagram-surface); + text-decoration: none; +} + +.nodeLink:hover { + border-color: var(--ifm-color-primary); + color: var(--diagram-ink); + text-decoration: none; +} + +.nodeHeader { + display: flex; + align-items: flex-start; + gap: 0.5rem; + min-width: 0; +} + +.nodeIcon, +.largeIcon { + display: grid; + flex: none; + place-items: center; + border: 1px solid var(--diagram-line); + color: var(--ifm-color-primary); + background: var(--diagram-panel); +} + +.nodeIcon { + width: 1.75rem; + height: 1.75rem; + border-radius: 0.45rem; +} + +.nodeIcon img { + width: 1.15rem; + height: 1.15rem; + object-fit: contain; +} + +.nodeCopy { + display: grid; + min-width: 0; +} + +.nodeCopy strong { + font-size: 0.72rem; + line-height: 1.25; +} + +.nodeCopy small { + color: var(--diagram-muted); + font-size: 0.59rem; + line-height: 1.35; +} + +.nodeBody { + display: grid; + align-content: start; + min-width: 0; +} + +.nodeBody code { + overflow: hidden; + display: block; + padding: 0.25rem 0.35rem; + border: 1px solid var(--diagram-line); + border-radius: 0.3rem; + color: var(--diagram-muted); + background: var(--diagram-panel); + font-size: 0.53rem; + text-overflow: ellipsis; + white-space: nowrap; +} + +.pillList { + display: flex; + flex-wrap: wrap; + gap: 0.25rem; +} + +.pillList span, +.pillList a { + padding: 0.15rem 0.3rem; + border: 1px solid var(--diagram-line); + border-radius: 999px; + color: var(--diagram-muted); + background: var(--diagram-panel); + font-size: 0.5rem; + line-height: 1.25; + text-decoration: none; +} + +.pillList a:hover { + border-color: var(--ifm-color-primary); + color: var(--ifm-color-primary); + text-decoration: none; +} + +.localDetails, +.definitionParts { + display: grid; + gap: 0.25rem; +} + +.localDetails span, +.definitionParts span { + display: flex; + align-items: center; + gap: 0.25rem; + color: var(--diagram-muted); + font-size: 0.53rem; + line-height: 1.3; +} + +.definitionParts svg { + flex: none; + color: var(--ifm-color-primary); +} + +.diagramNote { + padding-top: 0.75rem; + border-top: 1px solid var(--diagram-line); + color: var(--diagram-muted); + font-size: 0.68rem; + line-height: 1.45; +} + +.factList { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 0.4rem; +} + +.factList span { + display: flex; + align-items: center; + gap: 0.35rem; + min-width: 0; + padding: 0.45rem; + border: 1px solid var(--diagram-line); + border-radius: 0.4rem; + color: var(--diagram-muted); + background: var(--diagram-surface); + font-size: 0.56rem; + line-height: 1.3; +} + +.factList svg { + flex: none; + color: var(--ifm-color-primary); +} + +.boardSource { + display: flex; + align-items: center; + justify-self: center; + gap: 0.55rem; + min-width: 14rem; + padding: 0.65rem 0.8rem; + border: 1px solid var(--diagram-line); + border-radius: 0.55rem; + background: var(--diagram-surface); +} + +.largeIcon { + width: 2.25rem; + height: 2.25rem; + border-radius: 0.5rem; +} + +.boardSource > span:last-child { + display: grid; +} + +.boardSource strong { + font-size: 0.78rem; +} + +.boardSource small { + color: var(--diagram-muted); + font-size: 0.59rem; +} + +.layoutGrid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 0.55rem; +} + +.layoutCard { + display: grid; + gap: 0.55rem; + min-width: 0; + padding: 0.65rem; + border: 1px solid var(--diagram-line); + border-radius: 0.55rem; + margin: 0; + background: var(--diagram-surface); +} + +.layoutHeading { + display: flex; + align-items: center; + gap: 0.45rem; +} + +.layoutHeading > span:first-child { + display: grid; + flex: none; + place-items: center; + width: 1.65rem; + height: 1.65rem; + border: 1px solid var(--diagram-line); + border-radius: 0.4rem; + color: var(--ifm-color-primary); + background: var(--diagram-panel); +} + +.layoutHeading > span:last-child { + display: grid; + min-width: 0; +} + +.layoutHeading strong { + font-size: 0.7rem; +} + +.layoutHeading code { + padding: 0; + border: 0; + color: var(--diagram-muted); + background: transparent; + font-size: 0.54rem; + white-space: normal; +} + +.layoutCard > small { + color: var(--diagram-muted); + font-size: 0.55rem; +} + +.miniBoard { + display: grid; + grid-auto-rows: 1.2rem; + gap: 0.22rem; + min-height: 4.25rem; + padding: 0.35rem; + border: 1px dashed var(--diagram-line); + border-radius: 0.35rem; + background: var(--diagram-panel); +} + +.miniTile, +.miniRail { + display: block; + border: 1px solid var(--diagram-line); + border-radius: 0.22rem; + background: var(--diagram-surface); +} + +.miniTile:nth-child(2) { + border-color: var(--ifm-color-primary); +} + +.mobileBoard { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.mobileBoard .miniRail { + display: none; +} + +.mobileBoard .miniTile:nth-child(3), +.mobileBoard .miniTile:nth-child(5) { + grid-column: span 2; +} + +.baseBoard { + grid-template-columns: 0.7fr repeat(4, minmax(0, 1fr)); +} + +.baseBoard .miniRail { + grid-row: 1 / span 3; +} + +.baseBoard .miniTile:nth-child(3), +.baseBoard .miniTile:nth-child(4) { + grid-column: span 2; +} + +.customBoard { + grid-template-columns: repeat(5, minmax(0, 1fr)) 0.7fr; +} + +.customBoard .miniRail { + grid-column: 6; + grid-row: 1 / span 3; +} + +.customBoard .miniTile:nth-child(3) { + grid-column: span 3; +} + +.customBoard .miniTile:nth-child(5) { + grid-column: span 2; +} + +@media (max-width: 900px) { + .threeStepLane, + .fourStepLane { + grid-template-columns: minmax(0, 1fr); + } + + .node { + min-height: auto; + } + + .factList, + .layoutGrid { + grid-template-columns: minmax(0, 1fr); + } + + .miniBoard { + min-height: 5rem; + } +} diff --git a/apps/docs/src/components/pages/core-concepts/technical-diagrams.tsx b/apps/docs/src/components/pages/core-concepts/technical-diagrams.tsx new file mode 100644 index 000000000..0a6ff82e2 --- /dev/null +++ b/apps/docs/src/components/pages/core-concepts/technical-diagrams.tsx @@ -0,0 +1,423 @@ +import type { ReactNode } from "react"; + +import Link from "@docusaurus/Link"; +import { + IconApi, + IconBox, + IconBraces, + IconBrowser, + IconBuildingStore, + IconCode, + IconDeviceDesktop, + IconDeviceMobile, + IconKey, + IconLayoutBoard, + IconMessages, + IconPlugConnected, + IconRobot, + IconServer, + IconShieldCheck, + IconTool, + IconUser, + IconWorld, +} from "@tabler/icons-react"; + +import { sonarrIntegration } from "@site/docs/integrations/sonarr"; +import { FlowConnector } from "@site/src/components/ui/flow-connector"; + +import styles from "./technical-diagrams.module.css"; + +const sonarrIconUrl = getIconUrl(sonarrIntegration.iconUrl); + +export function AppFlowDiagram() { + return ( +
+
+ } title="App record" detail="Saved once in Homarr"> +
+ Name + Icon + URL + Ping URL · optional +
+
+ + } title="Board" detail="App tile or Bookmarks widget" /> + + } title="Browser" detail="Opens the app URL directly" /> +
+ + + If a Ping URL is set, the Homarr server checks that address for status. Clicking the tile still opens the app + URL. + +
+ ); +} + +export function IntegrationRoutesDiagram() { + return ( +
+
+ } title="Open the service" detail="Browser route" /> +
+ } title="App tile" detail="Click from a board" /> + + } title="App URL" detail="Browser-facing address"> + https://sonarr.example.com + + + } + title="Sonarr UI" + detail="The browser connects directly" + href="/docs/integrations/sonarr" + /> +
+
+ +
+ } title="Use service data" detail="Server route" /> +
+ } title="Widget" detail="Requests data or an action" /> + + } + title="Integration" + detail="URL and encrypted credentials" + href="/docs/management/integrations" + > + http://sonarr:8989 + + + } + title="Sonarr API" + detail="The Homarr server connects" + href="/docs/integrations/sonarr" + /> +
+
+ + + Linking the app to the integration gives integration-backed widgets the browser-facing destination. + +
+ ); +} + +export function BoardLayoutsDiagram() { + return ( +
+
+ + + + One board + The same apps, widgets, and Containers + +
+ + + +
+ } + title="Mobile" + range="starts at 0px" + detail="Own positions · no rails" + variant="mobile" + /> + } + title="Base" + range="starts at 768px" + detail="Own positions · rails available" + variant="base" + /> + } + title="Custom" + range="unique breakpoint" + detail="Own positions · rails available" + variant="custom" + /> +
+ + Moving or resizing an item in one layout does not change its coordinates in the others. +
+ ); +} + +export function AssistantFlowDiagram() { + return ( +
+
+ } title="Conversation" detail="Every request" /> +
+ } title="You" detail="Prompt, attachment, or @ reference" /> + + } + title="Assistant server" + detail="Loads live context and tool definitions" + /> + + } + title="Provider + model" + detail="Instance-wide provider; model may vary by conversation" + > +
+ Homarr + Hosted + Local + Custom +
+
+
+
+ +
+ } title="When the model calls a tool" detail="Only when needed" /> +
+ } title="Tool request" detail="Read data or make a change" /> + + } + title="Permission boundary" + detail="Current user; approval for changes by default" + /> + + } + title="Homarr resources" + detail="Boards · apps · integrations · widgets · services" + href="/docs/management/mcp" + /> +
+
+ + + Tool results return to the model; the final answer streams back to the same conversation. The Homarr provider + routes model requests through Workshop. Other providers connect directly from the Homarr server. + +
+ ); +} + +export function HomarrProviderDiagram() { + return ( +
+
+ } title="Assistant" detail="Per-user conversation" /> + + } title="Homarr server" detail="Context, permissions, and tools" /> + + } + title="Workshop provider" + detail="Quota and homarr/model routing" + href="/docs/workshop" + /> + + } title="Upstream model" detail="OpenRouter-compatible endpoint" /> +
+ +
+ + + + + + +
+ + + Tool calls still execute inside your Homarr instance with the signed-in user's permissions. + +
+ ); +} + +export function WorkshopFlowDiagram() { + return ( +
+
+ } title="Author" detail="Build shareable content"> +
+ Custom Widget JSON + Custom CSS +
+
+ + } + title="Workshop" + detail="Source, screenshots, and revision" + href="pathname:///workshop" + /> + + } + title="Review + import" + detail="Validate source and requested access" + /> + + } title="Your Homarr" detail="Configure and place on a board"> +
+ Widget → local URLs + secrets + CSS → board custom CSS +
+
+
+ + + Workshop stores the shareable definition. Instance-specific URLs and credentials stay local. + +
+ ); +} + +export function CustomWidgetFlowDiagram() { + return ( +
+
+ } + title="Widget definition" + detail="homarr-custom-widget-v2" + href="/docs/management/custom-widgets/authoring" + > +
+ + API sources + + + Queries + actions + + + Safe JSX + +
+
+ + } + title="Homarr runtime" + detail="Requests on the server; JSX in a restricted renderer" + href="/docs/management/custom-widgets/requests-and-security" + /> + + } title="Board tile" detail="Live data and declared actions" /> +
+ + + Source credentials are stored separately and excluded from exports, prompts, and Workshop submissions. + +
+ ); +} + +function RouteHeading({ icon, title, detail }: { icon: ReactNode; title: string; detail: string }) { + return ( +
+ {icon} + {title} + {detail} +
+ ); +} + +function DiagramNode({ + icon, + title, + detail, + href, + children, +}: { + icon: ReactNode; + title: string; + detail: string; + href?: string; + children?: ReactNode; +}) { + const content = ( + <> +
+ {icon} + + {title} + {detail} + +
+ {children &&
{children}
} + + ); + + if (href) { + return ( + + {content} + + ); + } + + return
{content}
; +} + +function LayoutCard({ + icon, + title, + range, + detail, + variant, +}: { + icon: ReactNode; + title: string; + range: string; + detail: string; + variant: "mobile" | "base" | "custom"; +}) { + return ( +
+
+ {icon} + + {title} + {range} + +
+ + {detail} +
+ ); +} + +function MiniBoard({ variant }: { variant: "mobile" | "base" | "custom" }) { + let className = styles.miniBoard; + className = `${className} ${styles[`${variant}Board`]}`; + + return ( + + ); +} + +function DiagramNote({ children }: { children: ReactNode }) { + return
{children}
; +} + +function getIconUrl(iconUrl: typeof sonarrIntegration.iconUrl) { + if (typeof iconUrl === "string") return iconUrl; + return iconUrl.light; +} diff --git a/apps/docs/src/components/pages/getting-started/concept-flow.module.css b/apps/docs/src/components/pages/getting-started/concept-flow.module.css new file mode 100644 index 000000000..cf0974be8 --- /dev/null +++ b/apps/docs/src/components/pages/getting-started/concept-flow.module.css @@ -0,0 +1,245 @@ +.diagram { + --diagram-ink: var(--ifm-font-color-base); + --diagram-muted: var(--ifm-color-emphasis-700); + --diagram-panel: var(--ifm-background-surface-color); + --diagram-line: var(--ifm-color-emphasis-300); + margin: 0; + padding: 1rem; + border: 1px solid var(--diagram-line); + border-radius: 0.75rem; + color: var(--diagram-ink); + background: var(--diagram-panel); +} + +.lane { + display: grid; + grid-template-columns: minmax(8.5rem, 1.1fr) 2.75rem minmax(8.5rem, 1fr) 2.75rem minmax(8.5rem, 1fr) 2.75rem minmax( + 8.5rem, + 1fr + ); + align-items: stretch; + gap: 0.35rem; +} + +.stage { + display: grid; + grid-template-rows: auto 1fr; + gap: 0.75rem; + min-width: 0; + padding: 0.7rem; + border: 1px solid var(--diagram-line); + border-radius: 0.55rem; + margin: 0; + background: var(--ifm-background-color); +} + +.stageHeading { + display: flex; + align-items: center; + gap: 0.5rem; + color: var(--diagram-ink); + text-decoration: none; +} + +a.stageHeading:hover { + color: var(--ifm-color-primary); + text-decoration: none; +} + +.stageHeading > span:last-child { + display: grid; + min-width: 0; +} + +.stageHeading strong { + font-size: 0.78rem; +} + +.stageHeading small { + color: var(--diagram-muted); + font-size: 0.62rem; + line-height: 1.3; +} + +.stageNumber { + display: grid; + flex: none; + place-items: center; + width: 1.45rem; + height: 1.45rem; + border: 1px solid var(--diagram-line); + border-radius: 50%; + color: var(--diagram-muted); + font-family: var(--font-mono); + font-size: 0.64rem; + font-weight: 700; +} + +.serviceList, +.widgetList { + display: grid; + align-content: center; + gap: 0.35rem; +} + +.service, +.widget { + display: flex; + align-items: center; + gap: 0.45rem; + min-width: 0; + padding: 0.4rem; + border: 1px solid var(--diagram-line); + border-radius: 0.4rem; + color: var(--diagram-ink); + background: var(--diagram-panel); + text-decoration: none; +} + +.service:hover, +.widget:hover { + border-color: var(--ifm-color-primary); + color: var(--diagram-ink); + text-decoration: none; +} + +.service img { + flex: none; + width: 1.25rem; + height: 1.25rem; +} + +.widget svg { + flex: none; + color: var(--diagram-muted); +} + +.service > span { + display: grid; + min-width: 0; +} + +.service strong, +.widget span { + overflow: hidden; + font-size: 0.67rem; + text-overflow: ellipsis; + white-space: nowrap; +} + +.service code, +.integration code { + padding: 0; + border: 0; + color: var(--diagram-muted); + background: transparent; + font-size: 0.56rem; + white-space: nowrap; +} + +.integration { + display: grid; + align-content: center; + justify-items: center; + gap: 0.35rem; + min-height: 5rem; + text-align: center; +} + +.integration > svg { + color: var(--diagram-muted); +} + +.integration > span { + color: var(--diagram-muted); + font-size: 0.61rem; + line-height: 1.35; +} + +.boardCalendar { + display: grid; + align-content: center; + gap: 0.28rem; + min-height: 5rem; + padding: 0.42rem; + border: 1px solid var(--diagram-line); + border-radius: 0.4rem; + background: var(--diagram-panel); +} + +.calendarHeader { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 0.3rem; +} + +.calendarHeader strong { + font-size: 0.58rem; +} + +.calendarHeader span { + color: var(--diagram-muted); + font-size: 0.44rem; +} + +.calendarWeekdays, +.calendarDays { + display: grid; + grid-template-columns: repeat(7, minmax(0, 1fr)); + gap: 0.12rem; +} + +.calendarWeekdays span { + color: var(--diagram-muted); + font-family: var(--font-mono); + font-size: 0.38rem; + text-align: center; +} + +.calendarDays span { + position: relative; + display: grid; + place-items: center; + min-width: 0; + aspect-ratio: 1; + border-radius: 0.18rem; + color: var(--diagram-muted); + background: color-mix(in srgb, var(--diagram-line) 28%, transparent); + font-family: var(--font-mono); + font-size: 0.42rem; +} + +.calendarDays span[data-event] { + color: var(--diagram-ink); + background: color-mix(in srgb, var(--diagram-line) 62%, transparent); + font-weight: 700; +} + +.calendarDays span[data-event]::after { + position: absolute; + bottom: 0.08rem; + width: 0.12rem; + height: 0.12rem; + border-radius: 50%; + background: var(--diagram-muted); + content: ""; +} + +@media (max-width: 900px) { + .lane { + grid-template-columns: minmax(0, 1fr); + } + + .serviceList, + .widgetList { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 430px) { + .serviceList, + .widgetList { + grid-template-columns: minmax(0, 1fr); + } +} diff --git a/apps/docs/src/components/pages/getting-started/concept-flow.tsx b/apps/docs/src/components/pages/getting-started/concept-flow.tsx new file mode 100644 index 000000000..7bf0609b4 --- /dev/null +++ b/apps/docs/src/components/pages/getting-started/concept-flow.tsx @@ -0,0 +1,154 @@ +import type { ReactNode } from "react"; + +import Link from "@docusaurus/Link"; +import { IconCalendar, IconDownload, IconPlugConnected } from "@tabler/icons-react"; + +import { qBittorentIntegration } from "@site/docs/integrations/q-bittorent"; +import { sonarrIntegration } from "@site/docs/integrations/sonarr"; +import { FlowConnector } from "@site/src/components/ui/flow-connector"; + +import styles from "./concept-flow.module.css"; + +const services = [ + { + name: sonarrIntegration.name, + iconUrl: getIconUrl(sonarrIntegration.iconUrl), + endpoint: "sonarr:8989", + href: "/docs/integrations/sonarr", + }, + { + name: qBittorentIntegration.name, + iconUrl: getIconUrl(qBittorentIntegration.iconUrl), + endpoint: "qbittorrent:8080", + href: "/docs/integrations/q-bittorent", + }, +]; + +const widgets = [ + { + name: "Calendar", + icon: IconCalendar, + href: "/docs/widgets/calendar", + }, + { + name: "Downloads", + icon: IconDownload, + href: "/docs/widgets/downloads", + }, +]; + +const calendarDays = Array.from({ length: 14 }, (_, index) => index + 1); +const calendarEventDays = new Set([3, 8, 12]); + +function getIconUrl(iconUrl: typeof sonarrIntegration.iconUrl) { + if (typeof iconUrl === "string") return iconUrl; + return iconUrl.light; +} + +export function ConceptFlow() { + return ( +
+
+ +
+ {services.map((service) => ( + + + + {service.name} + {service.endpoint} + + + ))} +
+
+ + + + +
+
+
+ + + + +
+ {widgets.map((widget) => { + const Icon = widget.icon; + return ( + +
+
+ + + + + + +
+
+ ); +} + +function Stage({ + number, + title, + detail, + href, + children, +}: { + number: string; + title: string; + detail: string; + href?: string; + children?: ReactNode; +}) { + const heading = ( + <> + {number} + + {title} + {detail} + + + ); + + return ( +
+ {href ? ( + + {heading} + + ) : ( +
{heading}
+ )} + {children} +
+ ); +} diff --git a/apps/docs/src/components/pages/getting-started/getting-started-overview.module.css b/apps/docs/src/components/pages/getting-started/getting-started-overview.module.css new file mode 100644 index 000000000..a6e84c68a --- /dev/null +++ b/apps/docs/src/components/pages/getting-started/getting-started-overview.module.css @@ -0,0 +1,232 @@ +.overview { + --start-ink: var(--ifm-font-color-base); + --start-muted: var(--ifm-color-emphasis-700); + --start-panel: var(--ifm-background-surface-color); + --start-line: var(--ifm-color-emphasis-300); + --start-coral: #fa5252; + display: grid; + gap: 1.5rem; + margin: 1.5rem 0 3rem; +} + +.intro { + padding-left: 1rem; + border-left: 3px solid var(--ifm-color-primary); +} + +.intro h2 { + margin: 0 0 0.4rem; + font-size: 1.5rem; +} + +.intro p { + max-width: 48rem; + margin: 0; + color: var(--start-muted); + line-height: 1.55; +} + +.editor { + display: grid; + gap: 0.9rem; + padding-top: 0.25rem; +} + +.editorHeading { + display: flex; + align-items: end; + justify-content: space-between; + gap: 1rem; +} + +.editorHeading h3 { + margin: 0 0 0.25rem; + font-size: 1.1rem; +} + +.editorHeading p { + margin: 0; + color: var(--start-muted); + font-size: 0.84rem; +} + +.editorHeading > a { + display: inline-flex; + flex: none; + align-items: center; + gap: 0.25rem; + font-size: 0.78rem; + font-weight: 700; +} + +.editorSteps { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 0.65rem; + margin: 0; + padding: 0; + list-style: none; +} + +.editorStep { + overflow: hidden; + display: grid; + grid-template-rows: auto 1fr; + min-width: 0; + border: 1px solid var(--start-line); + border-radius: 0.65rem; + background: var(--start-panel); +} + +.stepCopy { + display: flex; + align-items: center; + gap: 0.55rem; + padding: 0.65rem; +} + +.stepCopy > span { + display: grid; + flex: none; + place-items: center; + width: 1.4rem; + height: 1.4rem; + border: 1px solid var(--start-line); + border-radius: 50%; + color: var(--start-muted); + font-family: var(--font-mono); + font-size: 0.62rem; + font-weight: 700; +} + +.stepCopy > div { + display: grid; + min-width: 0; +} + +.stepCopy strong { + font-size: 0.78rem; +} + +.stepCopy small { + color: var(--start-muted); + font-size: 0.64rem; + line-height: 1.35; +} + +.stepMedia { + display: grid; + place-items: center; + min-height: 9rem; + padding: 0.4rem; + border-top: 1px solid var(--start-line); + background: #202020; +} + +.stepMedia img { + display: block; + width: 100%; + max-height: 12rem; + object-fit: contain; +} + +.stepMedia img[data-fit="cover"] { + height: 100%; + object-fit: cover; + object-position: top; +} + +.installPaths { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 0.8rem; + margin: 1rem 0 1.5rem; +} + +.installPath { + position: relative; + display: grid; + gap: 0.45rem; + min-height: 10rem; + padding: 1.1rem; + border: 1px solid var(--ifm-color-emphasis-400); + border-radius: 0.9rem; + color: var(--start-ink); + background: var(--start-panel); + box-shadow: 0 3px 10px rgb(20 25 35 / 8%); + text-decoration: none; + transition: + border-color 160ms ease, + transform 160ms ease, + box-shadow 160ms ease; +} + +.installPath:hover { + border-color: rgb(250 82 82 / 55%); + color: var(--start-ink); + text-decoration: none; + transform: translateY(-2px); + box-shadow: 0 12px 28px rgb(20 25 35 / 8%); +} + +.installPath > span { + color: #c92f2f; + font-family: var(--font-mono); + font-size: 0.62rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +:global([data-theme="dark"]) .installPath > span { + color: var(--ifm-color-primary-light); +} + +.installPath strong { + font-size: 1rem; +} + +.installPath small { + color: var(--start-muted); + line-height: 1.45; +} + +.installPath > svg { + position: absolute; + right: 0.9rem; + bottom: 0.9rem; + color: var(--start-coral); +} + +.recommendedPath { + border-color: var(--ifm-color-primary); + background: var(--start-panel); +} + +@media (max-width: 800px) { + .editorHeading { + align-items: start; + } + + .editorSteps { + grid-template-columns: minmax(0, 1fr); + } + + .stepMedia img { + max-height: 18rem; + } + + .installPaths { + grid-template-columns: 1fr; + } + + .installPath { + min-height: 8rem; + } +} + +@media (prefers-reduced-motion: reduce) { + .installPath { + transition: none; + } +} diff --git a/apps/docs/src/components/pages/getting-started/getting-started-overview.tsx b/apps/docs/src/components/pages/getting-started/getting-started-overview.tsx new file mode 100644 index 000000000..1f887c7da --- /dev/null +++ b/apps/docs/src/components/pages/getting-started/getting-started-overview.tsx @@ -0,0 +1,119 @@ +import Link from "@docusaurus/Link"; +import { IconArrowRight } from "@tabler/icons-react"; + +import addItem from "@site/docs/getting-started/img/manage-board-header-choose-item.png"; +import moveItem from "@site/docs/getting-started/img/move-item.gif"; +import resizeItem from "@site/docs/getting-started/img/resize-item.gif"; + +import { ConceptFlow } from "./concept-flow"; +import styles from "./getting-started-overview.module.css"; + +const editingSteps = [ + { + title: "Add", + description: "Choose an app, widget, or container.", + image: addItem, + alt: "Add item menu in board edit mode", + fit: "cover", + }, + { + title: "Move", + description: "Drag the item to another grid position.", + image: moveItem, + alt: "Dragging an app tile on a board", + fit: "contain", + }, + { + title: "Resize", + description: "Drag the resize handle to change its grid area.", + image: resizeItem, + alt: "Resizing an app tile on a board", + fit: "contain", + }, +]; + +export function GettingStartedOverview() { + return ( +
+
+

How Homarr works

+

Services expose data, integrations connect to them, widgets use the data, and boards arrange the widgets.

+
+ + + +
+
+
+

Board edit mode

+

Add items, move them, and resize them on the grid. Each viewport can have its own layout.

+
+ + Board docs
+ +
    + {editingSteps.map((step, index) => ( +
  1. +
    + {index + 1} +
    + {step.title} + {step.description} +
    +
    +
    + {step.alt} +
    +
  2. + ))} +
+
+
+ ); +} + +const installationPaths = [ + { + eyebrow: "Recommended", + title: "Docker Compose", + description: "General-purpose deployment with a persistent appdata volume.", + href: "/docs/getting-started/installation/docker", + recommended: true, + }, + { + eyebrow: "Kubernetes", + title: "Helm", + description: "Deploy Homarr into an existing cluster.", + href: "/docs/getting-started/installation/helm", + recommended: false, + }, + { + eyebrow: "Platforms", + title: "NAS and hosting guides", + description: "Unraid, TrueNAS, Synology, Portainer, Proxmox, and more.", + href: "/docs/category/installation-1", + recommended: false, + }, +]; + +export function InstallationPaths() { + return ( +
+ {installationPaths.map((path) => { + let className = styles.installPath; + if (path.recommended) className = `${className} ${styles.recommendedPath}`; + + return ( + + {path.eyebrow} + {path.title} + {path.description} +
+ ); +} diff --git a/apps/docs/src/components/ui/flow-connector.module.css b/apps/docs/src/components/ui/flow-connector.module.css new file mode 100644 index 000000000..d5494346d --- /dev/null +++ b/apps/docs/src/components/ui/flow-connector.module.css @@ -0,0 +1,175 @@ +.connector { + --flow-accent: var(--ifm-color-primary); + --flow-coral: #f17865; + --flow-head: var(--diagram-ink, var(--ifm-font-color-base)); + --flow-line: var(--diagram-line, var(--ifm-color-emphasis-300)); + --flow-rail: color-mix(in srgb, var(--flow-line) 68%, var(--flow-head)); + position: relative; + display: grid; + align-content: center; + justify-items: center; + gap: 0.22rem; + min-width: 0; + color: var(--flow-head); +} + +.label { + z-index: 1; + max-width: 100%; + padding: 0.17rem 0.36rem; + border: 1px solid color-mix(in srgb, var(--flow-accent) 32%, var(--flow-line)); + border-radius: 999px; + color: var(--diagram-muted, var(--ifm-color-emphasis-700)); + background: var(--diagram-panel, var(--ifm-background-surface-color)); + font-family: var(--font-mono); + font-size: 0.5rem; + font-weight: 650; + line-height: 1; + text-align: center; + white-space: nowrap; +} + +.track { + position: relative; + overflow: hidden; + display: block; + width: calc(100% + 0.5rem); + height: 1.1rem; + margin-inline: -0.25rem; +} + +.rail { + position: absolute; + top: 50%; + right: 0.18rem; + left: 0.18rem; + height: 2px; + background: var(--flow-rail); + transform: translateY(-50%); +} + +.beam { + position: absolute; + top: calc(50% - 1.5px); + left: 0.23rem; + width: 48%; + height: 3px; + border-radius: 999px; + background: linear-gradient(90deg, transparent, var(--flow-coral) 34%, var(--flow-accent) 68%, transparent); + filter: drop-shadow(0 0 0.28rem color-mix(in srgb, var(--flow-accent) 48%, transparent)); + animation: flow-beam-horizontal 2.4s cubic-bezier(0.4, 0, 0.2, 1) infinite; + animation-delay: var(--flow-delay); +} + +.vertical { + min-height: 3rem; +} + +.vertical .track { + width: 1.1rem; + height: 2.6rem; + margin-inline: 0; +} + +.vertical .rail { + top: 0.16rem; + right: auto; + bottom: 0.16rem; + left: 50%; + width: 2px; + height: auto; + transform: translateX(-50%); +} + +.vertical .beam { + top: 0.23rem; + left: calc(50% - 1.5px); + width: 3px; + height: 48%; + background: linear-gradient(180deg, transparent, var(--flow-coral) 46%, var(--flow-accent)); + animation-name: flow-beam-vertical; +} + +.visuallyHidden { + position: absolute; + overflow: hidden; + width: 1px; + height: 1px; + padding: 0; + border: 0; + margin: -1px; + clip: rect(0 0 0 0); + white-space: nowrap; +} + +@keyframes flow-beam-horizontal { + 0% { + opacity: 0; + transform: translateX(-35%); + } + + 18%, + 72% { + opacity: 1; + } + + 100% { + opacity: 0; + transform: translateX(155%); + } +} + +@keyframes flow-beam-vertical { + 0% { + opacity: 0; + transform: translateY(-35%); + } + + 18%, + 72% { + opacity: 1; + } + + 100% { + opacity: 0; + transform: translateY(155%); + } +} + +@media (max-width: 900px) { + .connector:not(.vertical) { + min-height: 3rem; + } + + .connector:not(.vertical) .track { + width: 1.1rem; + height: 2.6rem; + margin-inline: 0; + } + + .connector:not(.vertical) .rail { + top: 0.16rem; + right: auto; + bottom: 0.16rem; + left: 50%; + width: 2px; + height: auto; + transform: translateX(-50%); + } + + .connector:not(.vertical) .beam { + top: 0.23rem; + left: calc(50% - 1.5px); + width: 3px; + height: 48%; + background: linear-gradient(180deg, transparent, var(--flow-coral) 46%, var(--flow-accent)); + animation-name: flow-beam-vertical; + } +} + +@media (prefers-reduced-motion: reduce) { + .beam { + opacity: 1; + animation: none; + } +} diff --git a/apps/docs/src/components/ui/flow-connector.tsx b/apps/docs/src/components/ui/flow-connector.tsx new file mode 100644 index 000000000..b3cbd2ee8 --- /dev/null +++ b/apps/docs/src/components/ui/flow-connector.tsx @@ -0,0 +1,28 @@ +import type { CSSProperties } from "react"; + +import styles from "./flow-connector.module.css"; + +type FlowConnectorProps = { + label?: string; + animationDelay?: number; + orientation?: "responsive" | "vertical"; +}; + +export function FlowConnector({ label, animationDelay = 0, orientation = "responsive" }: FlowConnectorProps) { + let className = styles.connector; + if (orientation === "vertical") className = `${className} ${styles.vertical}`; + const style = { "--flow-delay": `${animationDelay}ms` } as CSSProperties; + + let accessibleLabel = then; + if (label) accessibleLabel = {label}; + + return ( + + {accessibleLabel} +