From 4dca4cc892c495e0d5a888d72dde8ce000e070a3 Mon Sep 17 00:00:00 2001 From: sgrtye <55668018+sgrtye@users.noreply.github.com> Date: Thu, 15 Feb 2024 07:18:37 +0000 Subject: [PATCH] Feature: Add list view for custom api (#2891) --------- Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com> --- docs/widgets/services/customapi.md | 49 +++++++++++- src/utils/config/service-helpers.js | 2 + src/widgets/customapi/component.jsx | 116 +++++++++++++++++++++++----- 3 files changed, 146 insertions(+), 21 deletions(-) diff --git a/docs/widgets/services/customapi.md b/docs/widgets/services/customapi.md index d392f0a9c..29b72633e 100644 --- a/docs/widgets/services/customapi.md +++ b/docs/widgets/services/customapi.md @@ -16,6 +16,7 @@ widget: password: password # auth - optional method: GET # optional, e.g. POST headers: # optional, must be object, see below + display: # optional, default to block, see below mappings: - field: key # needs to be YAML string or object label: Field 1 @@ -43,6 +44,15 @@ widget: locale: nl # optional style: short # optional - defaults to "long". Allowed values: `["long", "short", "narrow"]`. 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`. @@ -93,7 +103,7 @@ mappings: ## 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 - field: key4 @@ -110,7 +120,42 @@ You can manipulate data with the following tools `remap`, `scale` and `suffix`, label: Power format: float 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 diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index fb6757b6f..e203e6d7f 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -378,6 +378,7 @@ export function cleanServiceGroups(groups) { // customapi mappings, + display, // diskstation volume, @@ -539,6 +540,7 @@ export function cleanServiceGroups(groups) { } if (type === "customapi") { if (mappings) cleanedService.widget.mappings = mappings; + if (display) cleanedService.widget.display = display; if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval; } if (type === "calendar") { diff --git a/src/widgets/customapi/component.jsx b/src/widgets/customapi/component.jsx index 7e6ad4d73..726dcb602 100644 --- a/src/widgets/customapi/component.jsx +++ b/src/widgets/customapi/component.jsx @@ -90,6 +90,12 @@ function formatValue(t, mapping, rawValue) { // nothing } + // Apply fixed prefix. + const prefix = mapping?.prefix; + if (prefix) { + value = `${prefix} ${value}`; + } + // Apply fixed suffix. const suffix = mapping?.suffix; if (suffix) { @@ -99,12 +105,35 @@ function formatValue(t, mapping, rawValue) { 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 }) { const { t } = useTranslation(); const { widget } = service; - const { mappings = [], refreshInterval = 10000 } = widget; + const { mappings = [], refreshInterval = 10000, display = "block" } = widget; const { data: customData, error: customError } = useWidgetAPI(widget, null, { refreshInterval: Math.max(1000, refreshInterval), }); @@ -114,24 +143,73 @@ export default function Component({ service }) { } if (!customData) { - return ( - - {mappings.slice(0, 4).map((item) => ( - - ))} - - ); + switch (display) { + case "list": + return ( + +
+ {mappings.map((mapping) => ( +
+
{mapping.label}
+
+
-
+
+
+ ))} +
+
+ ); + + default: + return ( + + {mappings.slice(0, 4).map((item) => ( + + ))} + + ); + } } - return ( - - {mappings.slice(0, 4).map((mapping) => ( - - ))} - - ); + switch (display) { + case "list": + return ( + +
+ {mappings.map((mapping) => ( +
+
{mapping.label}
+
+
{formatValue(t, mapping, getValue(mapping.field, customData))}
+ {mapping.additionalField && ( +
+ {formatValue(t, mapping.additionalField, getValue(mapping.additionalField.field, customData))} +
+ )} +
+
+ ))} +
+
+ ); + + default: + return ( + + {mappings.slice(0, 4).map((mapping) => ( + + ))} + + ); + } }