Skip to content

Commit da17f1b

Browse files
Enhancement: multiple widgets per service (#4338)
Co-authored-by: shamoon <[email protected]>
1 parent 5ee2ea5 commit da17f1b

File tree

46 files changed

+210
-169
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+210
-169
lines changed

docs/configs/docker.md

+12
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,18 @@ labels:
153153
- homepage.widget.fields=["field1","field2"] # optional
154154
```
155155

156+
Multiple widgets can be specified by incrementing the index, e.g.
157+
158+
```yaml
159+
labels: ...
160+
- homepage.widget[0].type=emby
161+
- homepage.widget[0].url=http://emby.home
162+
- homepage.widget[0].key=yourembyapikeyhere
163+
- homepage.widget[1].type=uptimekuma
164+
- homepage.widget[1].url=http://uptimekuma.home
165+
- homepage.widget[1].slug=youreventslughere
166+
```
167+
156168
You can add specify fields for e.g. the [CustomAPI](../widgets/services/customapi.md) widget by using array-style dot notation:
157169

158170
```yaml

docs/configs/service-widgets.md

+19-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Service Widget Configuration
55

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

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

1010
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.
1111

@@ -22,6 +22,24 @@ Using Emby as an example, this is how you would attach the Emby service widget.
2222
key: apikeyapikeyapikeyapikeyapikey
2323
```
2424
25+
## Multiple Widgets
26+
27+
Each service can have multiple widgets attached to it, for example:
28+
29+
```yaml
30+
- Emby:
31+
icon: emby.png
32+
href: http://emby.host.or.ip/
33+
description: Movies & TV Shows
34+
widgets:
35+
- type: emby
36+
url: http://emby.host.or.ip
37+
key: apikeyapikeyapikeyapikeyapikey
38+
- type: uptimekuma
39+
url: http://uptimekuma.host.or.ip:port
40+
slug: statuspageslug
41+
```
42+
2543
## Field Visibility
2644
2745
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.

docs/widgets/index.md

+7-4
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ Service widgets are used to display the status of a service, often a web service
1919
description: Watch movies and TV shows.
2020
server: localhost
2121
container: plex
22-
widget:
23-
type: tautulli
24-
url: http://172.16.1.1:8181
25-
key: aabbccddeeffgghhiijjkkllmmnnoo
22+
widgets:
23+
- type: tautulli
24+
url: http://172.16.1.1:8181
25+
key: aabbccddeeffgghhiijjkkllmmnnoo
26+
- type: uptimekuma
27+
url: http://172.16.1.2:8080
28+
slug: aaaaaaabbbbb
2629
```
2730
2831
## Info Widgets

src/components/services/item.jsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,9 @@ export default function Item({ service, group, useEqualHeights }) {
154154
</div>
155155
)}
156156

157-
{service.widget && <Widget service={service} />}
157+
{service.widgets.map((widget) => (
158+
<Widget widget={widget} service={service} key={widget.index} />
159+
))}
158160
</div>
159161
</li>
160162
);

src/components/services/widget.jsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,24 @@ import { useTranslation } from "next-i18next";
33
import ErrorBoundary from "components/errorboundry";
44
import components from "widgets/components";
55

6-
export default function Widget({ service }) {
6+
export default function Widget({ widget, service }) {
77
const { t } = useTranslation("common");
88

9-
const ServiceWidget = components[service.widget.type];
9+
const ServiceWidget = components[widget.type];
1010

11+
const fullService = Object.apply({}, service);
12+
fullService.widget = widget;
1113
if (ServiceWidget) {
1214
return (
1315
<ErrorBoundary>
14-
<ServiceWidget service={service} />
16+
<ServiceWidget service={fullService} />
1517
</ErrorBoundary>
1618
);
1719
}
1820

1921
return (
2022
<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">
21-
<div className="font-thin text-sm">{t("widget.missing_type", { type: service.widget.type })}</div>
23+
<div className="font-thin text-sm">{t("widget.missing_type", { type: widget.type })}</div>
2224
</div>
2325
);
2426
}

src/pages/api/services/proxy.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ const logger = createLogger("servicesProxy");
99

1010
export default async function handler(req, res) {
1111
try {
12-
const { service, group } = req.query;
13-
const serviceWidget = await getServiceWidget(group, service);
12+
const { service, group, index } = req.query;
13+
const serviceWidget = await getServiceWidget(group, service, index);
1414
let type = serviceWidget?.type;
1515

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

44-
if (mapping.method && mapping.method !== req.method) {
44+
if (mapping?.method && mapping.method !== req.method) {
4545
logger.debug("Unsupported method: %s", req.method);
4646
return res.status(403).json({ error: "Unsupported method" });
4747
}

0 commit comments

Comments
 (0)