Skip to content

Commit

Permalink
Enhancement: multiple widgets per service (gethomepage#4338)
Browse files Browse the repository at this point in the history
  • Loading branch information
shamoon committed Nov 27, 2024
1 parent 385511f commit 907abee
Show file tree
Hide file tree
Showing 46 changed files with 210 additions and 169 deletions.
12 changes: 12 additions & 0 deletions docs/configs/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,18 @@ labels:
- homepage.widget.fields=["field1","field2"] # optional
```

Multiple widgets can be specified by incrementing the index, e.g.

```yaml
labels: ...
- homepage.widget[0].type=emby
- homepage.widget[0].url=http://emby.home
- homepage.widget[0].key=yourembyapikeyhere
- homepage.widget[1].type=uptimekuma
- homepage.widget[1].url=http://uptimekuma.home
- homepage.widget[1].slug=youreventslughere
```

You can add specify fields for e.g. the [CustomAPI](../widgets/services/customapi.md) widget by using array-style dot notation:

```yaml
Expand Down
20 changes: 19 additions & 1 deletion docs/configs/service-widgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Service Widget Configuration

Unless otherwise noted, URLs should not end with a `/` or other API path. Each widget will handle the path on its own.

Each service can have one widget attached to it (often matching the service type, but that's not forced).
Each service can have widgets attached to it (often matching the service type, but that's not forced).

In addition to the href of the service, you can also specify the target location in which to open that link. See [Link Target](settings.md#link-target) for more details.

Expand All @@ -22,6 +22,24 @@ Using Emby as an example, this is how you would attach the Emby service widget.
key: apikeyapikeyapikeyapikeyapikey
```
## Multiple Widgets
Each service can have multiple widgets attached to it, for example:
```yaml
- Emby:
icon: emby.png
href: http://emby.host.or.ip/
description: Movies & TV Shows
widgets:
- type: emby
url: http://emby.host.or.ip
key: apikeyapikeyapikeyapikeyapikey
- type: uptimekuma
url: http://uptimekuma.host.or.ip:port
slug: statuspageslug
```
## Field Visibility
Each widget can optionally provide a list of which fields should be visible via the `fields` widget property. If no fields are specified, then all fields will be displayed. The `fields` property must be a valid YAML array of strings. As an example, here is the entry for Sonarr showing only a couple of fields.
Expand Down
11 changes: 7 additions & 4 deletions docs/widgets/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ Service widgets are used to display the status of a service, often a web service
description: Watch movies and TV shows.
server: localhost
container: plex
widget:
type: tautulli
url: http://172.16.1.1:8181
key: aabbccddeeffgghhiijjkkllmmnnoo
widgets:
- type: tautulli
url: http://172.16.1.1:8181
key: aabbccddeeffgghhiijjkkllmmnnoo
- type: uptimekuma
url: http://172.16.1.2:8080
slug: aaaaaaabbbbb
```
## Info Widgets
Expand Down
4 changes: 3 additions & 1 deletion src/components/services/item.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ export default function Item({ service, group, useEqualHeights }) {
</div>
)}

{service.widget && <Widget service={service} />}
{service.widgets.map((widget) => (
<Widget widget={widget} service={service} key={widget.index} />
))}
</div>
</li>
);
Expand Down
10 changes: 6 additions & 4 deletions src/components/services/widget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,24 @@ import { useTranslation } from "next-i18next";
import ErrorBoundary from "components/errorboundry";
import components from "widgets/components";

export default function Widget({ service }) {
export default function Widget({ widget, service }) {
const { t } = useTranslation("common");

const ServiceWidget = components[service.widget.type];
const ServiceWidget = components[widget.type];

const fullService = Object.apply({}, service);
fullService.widget = widget;
if (ServiceWidget) {
return (
<ErrorBoundary>
<ServiceWidget service={service} />
<ServiceWidget service={fullService} />
</ErrorBoundary>
);
}

return (
<div className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center p-1 service-missing">
<div className="font-thin text-sm">{t("widget.missing_type", { type: service.widget.type })}</div>
<div className="font-thin text-sm">{t("widget.missing_type", { type: widget.type })}</div>
</div>
);
}
6 changes: 3 additions & 3 deletions src/pages/api/services/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const logger = createLogger("servicesProxy");

export default async function handler(req, res) {
try {
const { service, group } = req.query;
const serviceWidget = await getServiceWidget(group, service);
const { service, group, index } = req.query;
const serviceWidget = await getServiceWidget(group, service, index);
let type = serviceWidget?.type;

// exceptions
Expand Down Expand Up @@ -41,7 +41,7 @@ export default async function handler(req, res) {
const endpoint = mapping?.endpoint;
const endpointProxy = mapping?.proxyHandler || serviceProxyHandler;

if (mapping.method && mapping.method !== req.method) {
if (mapping?.method && mapping.method !== req.method) {
logger.debug("Unsupported method: %s", req.method);
return res.status(403).json({ error: "Unsupported method" });
}
Expand Down
Loading

0 comments on commit 907abee

Please sign in to comment.