-

-
-

-

-
+
+

+
### Supported Integrations
diff --git a/apps/docs/docs/widgets/custom-api/index.mdx b/apps/docs/docs/widgets/custom-api/index.mdx
index 908625499..d7eb59617 100644
--- a/apps/docs/docs/widgets/custom-api/index.mdx
+++ b/apps/docs/docs/widgets/custom-api/index.mdx
@@ -32,7 +32,8 @@ Credentials remain on the server.
:::note
Custom API widgets must first be created in **Management → Custom Widgets** before they appear in the widget picker.
-Action buttons can only be executed by administrators.
+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.
:::
### Permissions and actions
diff --git a/apps/docs/docs/widgets/dns-hole-controls/index.mdx b/apps/docs/docs/widgets/dns-hole-controls/index.mdx
index e97407da7..387431190 100644
--- a/apps/docs/docs/widgets/dns-hole-controls/index.mdx
+++ b/apps/docs/docs/widgets/dns-hole-controls/index.mdx
@@ -22,7 +22,7 @@ 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, while cards and controls adapt to the widget's width and height.
+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, while cards and controls adapt to the widget's width and height. Bulk actions keep successful results visible and report the number of failures.
### Screenshots
diff --git a/apps/docs/docs/widgets/docker-containers/img/table.png b/apps/docs/docs/widgets/docker-containers/img/table.png
index ff5aa337a..43ad6a279 100644
Binary files a/apps/docs/docs/widgets/docker-containers/img/table.png and b/apps/docs/docs/widgets/docker-containers/img/table.png differ
diff --git a/apps/docs/docs/widgets/docker-containers/index.mdx b/apps/docs/docs/widgets/docker-containers/index.mdx
index 1959ca959..bd0e2ee19 100644
--- a/apps/docs/docs/widgets/docker-containers/index.mdx
+++ b/apps/docs/docs/widgets/docker-containers/index.mdx
@@ -8,6 +8,7 @@ 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 { WidgetInteractionGuide } from "@site/src/components/widgets/interactions";
import { IconAd } from "@tabler/icons-react";
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
@@ -49,6 +50,8 @@ 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/img/advanced-view.png b/apps/docs/docs/widgets/downloads/img/advanced-view.png
new file mode 100644
index 000000000..042e713c3
Binary files /dev/null and b/apps/docs/docs/widgets/downloads/img/advanced-view.png differ
diff --git a/apps/docs/docs/widgets/downloads/img/filter-panel.png b/apps/docs/docs/widgets/downloads/img/filter-panel.png
new file mode 100644
index 000000000..e819e80f9
Binary files /dev/null and b/apps/docs/docs/widgets/downloads/img/filter-panel.png differ
diff --git a/apps/docs/docs/widgets/downloads/index.mdx b/apps/docs/docs/widgets/downloads/index.mdx
index 425efb0a7..85bace5e3 100644
--- a/apps/docs/docs/widgets/downloads/index.mdx
+++ b/apps/docs/docs/widgets/downloads/index.mdx
@@ -21,36 +21,79 @@ import { downloadsWidget } from ".";
-This widget displays a list of torrents or usenet-articles that are currently being downloaded, along with their progress and other relevant information. It supports 7 download client integrations and provides a rich, responsive table interface.
+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.
### Screenshots
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";
-#### Right-click context menu
+#### Download-row context menu
-

+

+
+
+#### Advanced view
+
+
+

+
+
+#### Advanced filter panel
+
+
+
### Features
-- **Responsive table** — columns automatically adapt to widget width, hiding less important columns at smaller sizes
-- **Sortable columns** — click any column header to sort ascending/descending
+- **Responsive compact table** — in compact mode, selected columns adapt to both widget width and height; narrow or short tiles hide speed/state columns, and the shortest tiles also hide the ETA column
+- **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
-- **Right-click context menu** — copy download names, or pause, resume, and delete when your account has Interact access and the client supports those actions
+- **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** — toggle a summary bar showing queue progress, total size, speeds, ratio, and per-state counts
+- **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 downloads from supported clients when your account has Interact access; read-only clients such as slskd do not expose these controls
+- **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 displayed in the footer
+- **Speed overview** — total download and upload speeds for the selected clients are displayed in the footer
+
+:::note
+
+Compact layouts use both dimensions: below 500px wide, speed columns are hidden; below 300px wide, the ETA and state
+columns are hidden too. A tile shorter than 180px hides speed and state columns, and a tile shorter than 120px also
+hides ETA. The footer is hidden below 96px in compact mode. Advanced view bypasses these compact size 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
@@ -82,20 +125,20 @@ import contextMenuImg from "./img/context-menu.png";
},
{
integration: slskdIntegration,
- note: "Soulseek client (read-only)",
+ note: "Soulseek client (list-only; mutation controls are no-ops)",
},
]}
/>
### Interactions
-- **Right-click** any download to copy its name; pause/resume and delete require Interact access and client support
+- **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 from the footer
-- **Pause / Resume** downloads from supported clients using the footer controls when you have Interact access; slskd remains read-only
-- **Filter** by integration or status using the filter button in the footer
-- **Sort** the current view by clicking column headers to switch direction
+- **Stats toggle** — show or hide the global stats bar in compact mode; advanced view always shows the stats bar
+- **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
diff --git a/apps/docs/docs/widgets/downloads/index.ts b/apps/docs/docs/widgets/downloads/index.ts
index fba87aad1..f4e1945b1 100644
--- a/apps/docs/docs/widgets/downloads/index.ts
+++ b/apps/docs/docs/widgets/downloads/index.ts
@@ -30,19 +30,20 @@ export const downloadsWidget: WidgetDefinition = {
{
name: "Columns to show",
description:
- "Select the columns you want to display in the widget. Columns automatically hide/show based on widget width.",
+ "Select the columns you want to display in the widget. Compact layouts automatically hide/show selected columns based on widget width and height; advanced view keeps the selected columns visible.",
values: `List of columns: ${columnsList.join(", ")}`,
defaultValue: ["name", "progress", "downSpeed", "time", "state"].join(", "),
},
{
name: "Default sort column",
- description: "The column used for initial sorting when the widget loads.",
+ description:
+ "The column used for initial sorting when the widget loads. Clicking a column header changes the current view only.",
defaultValue: "progress",
values: `List of columns: ${sortColumns.join(", ")}`,
},
{
name: "Invert sorting",
- description: "This will invert the default sorting order.",
+ description: "This sets the initial sorting direction.",
values: { type: "boolean" },
defaultValue: "no",
},
@@ -66,8 +67,7 @@ export const downloadsWidget: WidgetDefinition = {
},
{
name: "Hide completed torrent under this threshold (in kiB/s)",
- description:
- "This will hide completed torrent entries that have an upload speed below the specified threshold.",
+ description: "This will hide completed torrent entries whose upload speed is below the specified threshold.",
values: "Any number above 0, 0 to disable",
defaultValue: "0",
},
@@ -85,15 +85,16 @@ export const downloadsWidget: WidgetDefinition = {
defaultValue: "no",
},
{
- name: "Use filter to calculate Ratio",
- description: "This will use the category filter when calculating the global torrent ratio.",
+ name: "Use category filter for global torrent ratio",
+ description:
+ "When enabled, the configured category/label filter is applied to the global torrent ratio. Footer client/status filters do not change this ratio.",
values: { type: "boolean" },
defaultValue: "yes",
},
{
name: "Limit items per integration",
description: "This will limit the number of items shown per integration, not globally.",
- values: "Any number above 1",
+ values: "Any whole number from 1 upward",
defaultValue: "50",
},
],
diff --git a/apps/docs/docs/widgets/media-server/img/advanced-view.png b/apps/docs/docs/widgets/media-server/img/advanced-view.png
new file mode 100644
index 000000000..75a49a3a2
Binary files /dev/null and b/apps/docs/docs/widgets/media-server/img/advanced-view.png differ
diff --git a/apps/docs/docs/widgets/media-server/img/table.png b/apps/docs/docs/widgets/media-server/img/table.png
index d8153d22f..9100a7a8c 100644
Binary files a/apps/docs/docs/widgets/media-server/img/table.png and b/apps/docs/docs/widgets/media-server/img/table.png differ
diff --git a/apps/docs/docs/widgets/media-server/index.mdx b/apps/docs/docs/widgets/media-server/index.mdx
index a8a9a517e..0c4dc18d0 100644
--- a/apps/docs/docs/widgets/media-server/index.mdx
+++ b/apps/docs/docs/widgets/media-server/index.mdx
@@ -31,8 +31,12 @@ Sessions without user metadata remain visible and are labeled as an unknown user
### Screenshots
import mediaTable from "./img/table.png";
+import mediaAdvancedView from "./img/advanced-view.png";
-

+
+

+

+
### Supported Integrations
diff --git a/apps/docs/docs/widgets/weather/img/advanced-view.png b/apps/docs/docs/widgets/weather/img/advanced-view.png
new file mode 100644
index 000000000..96e37daf4
Binary files /dev/null and b/apps/docs/docs/widgets/weather/img/advanced-view.png differ
diff --git a/apps/docs/docs/widgets/weather/index.mdx b/apps/docs/docs/widgets/weather/index.mdx
index f36dc68ea..f64f5d754 100644
--- a/apps/docs/docs/widgets/weather/index.mdx
+++ b/apps/docs/docs/widgets/weather/index.mdx
@@ -15,17 +15,20 @@ import { weatherWidget } from ".";
The Weather Widget uses your location to display the current, highest and lowest temperature.
In the compact view, select a condition icon or forecast day to open details with a mouse, keyboard or touch.
-The advanced view always combines current conditions with the full seven-day forecast, including humidity, wind,
-gusts, sunrise and sunset. Both views reuse the same cached Open Meteo response.
+The compact forecast shows up to the configured number of days. The advanced view combines current conditions with the
+available daily forecast, including humidity, wind, gusts, sunrise and sunset. Both views reuse the same cached Open
+Meteo response.
### Screenshots
import forecastWeather from "./img/forecast.png";
import currentWeather from "./img/current.png";
+import advancedWeather from "./img/advanced-view.png";
diff --git a/apps/docs/src/components/widgets/interactions.tsx b/apps/docs/src/components/widgets/interactions.tsx
index c75102f92..14fdbf0ee 100644
--- a/apps/docs/src/components/widgets/interactions.tsx
+++ b/apps/docs/src/components/widgets/interactions.tsx
@@ -1,10 +1,10 @@
-import { IconArrowsMaximize, IconLayoutGrid, IconMouse2, IconPlus } from "@tabler/icons-react";
+import { IconArrowsMaximize, IconLayoutGrid, IconMouse2, IconRefresh } from "@tabler/icons-react";
const advancedInteraction = {
icon: IconArrowsMaximize,
title: "Advanced view",
description:
- "Hold Shift while hovering for an in-place preview, press Shift + Enter, or choose Open advanced view from the widget menu.",
+ "Supported widgets explicitly opt into advanced view. Focus a widget and press Shift + Enter, hold Shift while hovering for about 500 ms, or choose Open advanced view from its menu. It is unavailable in edit mode and remains compact-only on widgets that do not opt in.",
} as const;
const standardInteractions = [
@@ -12,19 +12,19 @@ const standardInteractions = [
icon: IconMouse2,
title: "Widget actions",
description:
- "Right-click for live query status, refresh, settings, quick options, and actions supported by the widget.",
- },
- {
- icon: IconPlus,
- title: "Place it precisely",
- description:
- "With board changes allowed, right-click or touch and hold empty grid space to add there. Keyboard users can press Shift + F10.",
+ "Signed-in users can open the widget context menu outside edit mode when Enable right click on widgets is enabled. App tiles are excluded. Settings, quick options, and integration actions appear or enable only when the widget and your board or integration permissions allow them.",
},
{
icon: IconLayoutGrid,
title: "Adaptive detail",
description:
- "Resize a widget to tune its density. Compact views keep primary status visible, then reveal details and controls as space or intent allows.",
+ "Resize a widget to tune its density. Compact layouts hide lower-priority details and controls as space shrinks; compact-only widgets adapt in place instead of opening a separate advanced view.",
+ },
+ {
+ icon: IconRefresh,
+ title: "Data status",
+ description:
+ "Widgets distinguish initial loading, successful empty results, terminal errors, stale cached data, and partial integration failures as applicable. Initial loads use a loading state, empty results use an empty state, and terminal failures can offer retry; retained data can stay visible with a stale warning, while healthy integrations can remain visible when another source fails. The shared menu reports Loading while matching active queries fetch, Idle when none are active, Error when any match is in error, otherwise Success with the latest data age when available. Refresh refetches only active queries owned by that widget and view and is disabled while they fetch.",
},
] as const;
@@ -35,14 +35,12 @@ export const WidgetInteractionGuide = ({ advancedView = true }: { advancedView?:
Power-user controls
- Show shortcuts
+ Show controls
- Hide shortcuts
+ Hide controls
-
+
{interactions.map(({ icon: Icon, title, description }) => (
@@ -53,8 +51,13 @@ export const WidgetInteractionGuide = ({ advancedView = true }: { advancedView?:
{advancedView && (
- Advanced view reuses the widget's live data and cache. The rest of the board stays visible but dimmed. On
- touch devices, use the widget menu; compact-only widgets adapt in place instead.
+ Advanced view reuses existing data where possible; some widgets request additional or denser data. Hold Shift
+ while hovering a supported widget for a temporary preview; it opens after about 500 ms and closes when Shift
+ is released, the pointer leaves, or the window loses focus. For a persistent view, focus the widget and press
+ Shift + Enter or use Open advanced view from its menu. Manual view closes with Escape after nested menus or
+ popovers handle their own Escape, its close button, or the backdrop; it restores focus, traps focus, and locks
+ background scrolling. Shift + wheel scrolls a scrollable advanced panel when it can consume the event. On
+ touch devices, use the widget menu when available; compact-only widgets adapt in place instead.
)}