mirror of
https://github.com/karl0ss/homepage.git
synced 2025-05-03 05:53:40 +01:00
Feature: Add list view for custom api (#2891)
--------- Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
This commit is contained in:
parent
ea0310548a
commit
4dca4cc892
@ -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
|
||||
|
@ -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") {
|
||||
|
@ -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 (
|
||||
<Container service={service}>
|
||||
{mappings.slice(0, 4).map((item) => (
|
||||
<Block label={item.label} key={item.label} />
|
||||
))}
|
||||
</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 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 (
|
||||
<Container service={service}>
|
||||
{mappings.slice(0, 4).map((item) => (
|
||||
<Block label={item.label} key={item.label} />
|
||||
))}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Container service={service}>
|
||||
{mappings.slice(0, 4).map((mapping) => (
|
||||
<Block
|
||||
label={mapping.label}
|
||||
key={mapping.label}
|
||||
value={formatValue(t, mapping, getValue(mapping.field, customData))}
|
||||
/>
|
||||
))}
|
||||
</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 (
|
||||
<Container service={service}>
|
||||
{mappings.slice(0, 4).map((mapping) => (
|
||||
<Block
|
||||
label={mapping.label}
|
||||
key={mapping.label}
|
||||
value={formatValue(t, mapping, getValue(mapping.field, customData))}
|
||||
/>
|
||||
))}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user