Feature: Add list view for custom api (#2891)

---------

Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
pull/2916/head
sgrtye 9 months ago committed by GitHub
parent ea0310548a
commit 4dca4cc892
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -16,6 +16,7 @@ widget:
password: password # auth - optional password: password # auth - optional
method: GET # optional, e.g. POST method: GET # optional, e.g. POST
headers: # optional, must be object, see below headers: # optional, must be object, see below
display: # optional, default to block, see below
mappings: mappings:
- field: key # needs to be YAML string or object - field: key # needs to be YAML string or object
label: Field 1 label: Field 1
@ -43,6 +44,15 @@ widget:
locale: nl # optional locale: nl # optional
style: short # optional - defaults to "long". Allowed values: `["long", "short", "narrow"]`. style: short # optional - defaults to "long". Allowed values: `["long", "short", "narrow"]`.
numeric: auto # optional - defaults to "always". Allowed values `["always", "auto"]`. numeric: auto # optional - defaults to "always". Allowed values `["always", "auto"]`.
- field: key
label: Field 6
format: text
additionalField: # optional
field:
hourly:
time: other key
color: theme # optional - defaults to "". Allowed values: `["theme", "adaptive", "black", "white"]`.
format: date # optional
``` ```
Supported formats for the values are `text`, `number`, `float`, `percent`, `bytes`, `bitrate`, `date` and `relativeDate`. Supported formats for the values are `text`, `number`, `float`, `percent`, `bytes`, `bitrate`, `date` and `relativeDate`.
@ -93,7 +103,7 @@ mappings:
## Data Transformation ## Data Transformation
You can manipulate data with the following tools `remap`, `scale` and `suffix`, for example: You can manipulate data with the following tools `remap`, `scale`, `prefix` and `suffix`, for example:
```yaml ```yaml
- field: key4 - field: key4
@ -110,7 +120,42 @@ You can manipulate data with the following tools `remap`, `scale` and `suffix`,
label: Power label: Power
format: float format: float
scale: 0.001 # can be number or string e.g. 1/16 scale: 0.001 # can be number or string e.g. 1/16
suffix: kW suffix: "kW"
- field: key6
label: Price
format: float
prefix: "$"
```
## List View
You can change the default block view to a list view by setting the `display` option to `list`.
The list view can optionally display an additional field next to the primary field.
`additionalField`: Similar to `field`, but only used in list view. Displays additional information for the mapping object on the right.
`field`: Defined the same way as other custom api widget fields.
`color`: Allowed options: `"theme", "adaptive", "black", "white"`. The option `adaptive` will apply a color using the value of the `additionalField`, green for positive numbers, red for negative numbers.
```yaml
- field: key
label: Field
format: text
remap:
- value: 0
to: None
- value: 1
to: Connected
- any: true # will map all other values
to: Unknown
additionalField:
field:
hourly:
time: key
color: theme
format: date
``` ```
## Custom Headers ## Custom Headers

@ -378,6 +378,7 @@ export function cleanServiceGroups(groups) {
// customapi // customapi
mappings, mappings,
display,
// diskstation // diskstation
volume, volume,
@ -539,6 +540,7 @@ export function cleanServiceGroups(groups) {
} }
if (type === "customapi") { if (type === "customapi") {
if (mappings) cleanedService.widget.mappings = mappings; if (mappings) cleanedService.widget.mappings = mappings;
if (display) cleanedService.widget.display = display;
if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval; if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval;
} }
if (type === "calendar") { if (type === "calendar") {

@ -90,6 +90,12 @@ function formatValue(t, mapping, rawValue) {
// nothing // nothing
} }
// Apply fixed prefix.
const prefix = mapping?.prefix;
if (prefix) {
value = `${prefix} ${value}`;
}
// Apply fixed suffix. // Apply fixed suffix.
const suffix = mapping?.suffix; const suffix = mapping?.suffix;
if (suffix) { if (suffix) {
@ -99,12 +105,35 @@ function formatValue(t, mapping, rawValue) {
return value; return value;
} }
function getColor(mapping, customData) {
const value = getValue(mapping.additionalField.field, customData);
const { color } = mapping.additionalField;
switch (color) {
case "adaptive":
try {
const number = parseFloat(value);
return number > 0 ? "text-emerald-300" : "text-rose-300";
} catch (e) {
return "";
}
case "black":
return `text-black`;
case "white":
return `text-white`;
case "theme":
return `text-theme-500`;
default:
return "";
}
}
export default function Component({ service }) { export default function Component({ service }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { widget } = service; const { widget } = service;
const { mappings = [], refreshInterval = 10000 } = widget; const { mappings = [], refreshInterval = 10000, display = "block" } = widget;
const { data: customData, error: customError } = useWidgetAPI(widget, null, { const { data: customData, error: customError } = useWidgetAPI(widget, null, {
refreshInterval: Math.max(1000, refreshInterval), refreshInterval: Math.max(1000, refreshInterval),
}); });
@ -114,6 +143,27 @@ export default function Component({ service }) {
} }
if (!customData) { if (!customData) {
switch (display) {
case "list":
return (
<Container service={service}>
<div className="flex flex-col w-full">
{mappings.map((mapping) => (
<div
key={mapping.label}
className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-row items-center justify-between p-1 text-xs animate-pulse"
>
<div className="font-thin pl-2">{mapping.label}</div>
<div className="flex flex-row text-right">
<div className="font-bold mr-2">-</div>
</div>
</div>
))}
</div>
</Container>
);
default:
return ( return (
<Container service={service}> <Container service={service}>
{mappings.slice(0, 4).map((item) => ( {mappings.slice(0, 4).map((item) => (
@ -122,7 +172,34 @@ export default function Component({ service }) {
</Container> </Container>
); );
} }
}
switch (display) {
case "list":
return (
<Container service={service}>
<div className="flex flex-col w-full">
{mappings.map((mapping) => (
<div
key={mapping.label}
className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-row items-center justify-between p-1 text-xs"
>
<div className="font-thin pl-2">{mapping.label}</div>
<div className="flex flex-row text-right">
<div className="font-bold mr-2">{formatValue(t, mapping, getValue(mapping.field, customData))}</div>
{mapping.additionalField && (
<div className={`font-bold mr-2 ${getColor(mapping, customData)}`}>
{formatValue(t, mapping.additionalField, getValue(mapping.additionalField.field, customData))}
</div>
)}
</div>
</div>
))}
</div>
</Container>
);
default:
return ( return (
<Container service={service}> <Container service={service}>
{mappings.slice(0, 4).map((mapping) => ( {mappings.slice(0, 4).map((mapping) => (
@ -134,4 +211,5 @@ export default function Component({ service }) {
))} ))}
</Container> </Container>
); );
}
} }

Loading…
Cancel
Save