From 3b18dc1f45b68324210ca49308fdc28d27aa155e Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 22 Sep 2026 18:21:35 -0700 Subject: [PATCH] Extract helpers --- src/widgets/customapi/component.jsx | 152 +--------------------------- src/widgets/customapi/utils.js | 151 +++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 150 deletions(-) create mode 100644 src/widgets/customapi/utils.js diff --git a/src/widgets/customapi/component.jsx b/src/widgets/customapi/component.jsx index af94434da..bccfe430e 100644 --- a/src/widgets/customapi/component.jsx +++ b/src/widgets/customapi/component.jsx @@ -1,161 +1,13 @@ import classNames from "classnames"; import { useTranslation } from "next-i18next/pages"; +import { formatValue, getColor, getValue } from "./utils"; + import Block from "components/services/widget/block"; import Container from "components/services/widget/container"; import * as shvl from "utils/config/shvl"; import useWidgetAPI from "utils/proxy/use-widget-api"; -function getValue(field, data) { - let value = data; - let lastField = field; - let key = ""; - - // Support APIs that return arrays or scalars directly. - if (typeof field === "undefined") { - return value; - } - - // shvl is easier, everything else is kept for backwards compatibility. - if (typeof field === "string") { - return shvl.get(data, field, null) ?? data[field] ?? null; - } - - while (typeof lastField === "object") { - key = Object.keys(lastField)[0] ?? null; - - if (key === null) { - break; - } - - value = value[key]; - lastField = lastField[key]; - } - - if (typeof value === "undefined") { - return null; - } - - return value[lastField] ?? null; -} - -function getSize(data) { - if (Array.isArray(data) || typeof data === "string") { - return data.length; - } else if (typeof data === "object" && data !== null) { - return Object.keys(data).length; - } - - return NaN; -} - -function formatValue(t, mapping, rawValue) { - let value = rawValue; - - // Remap the value. - const remaps = mapping?.remap ?? []; - for (let i = 0; i < remaps.length; i += 1) { - const remap = remaps[i]; - if (remap?.any || remap?.value === value) { - value = remap.to; - break; - } - } - - // Scale the value. Accepts either a number to multiply by or a string - // like "12/345". - const scale = mapping?.scale; - if (typeof scale === "number") { - value *= scale; - } else if (typeof scale === "string") { - const parts = scale.split("/"); - const numerator = parts[0] ? parseFloat(parts[0]) : 1; - const denominator = parts[1] ? parseFloat(parts[1]) : 1; - value = (value * numerator) / denominator; - } - - // Format the value using a known type. - switch (mapping?.format) { - case "number": - value = t("common.number", { value: parseInt(value, 10) }); - break; - case "float": - value = t("common.number", { value }); - break; - case "percent": - value = t("common.percent", { value }); - break; - case "duration": - value = t("common.duration", { value }); - break; - case "bytes": - value = t("common.bytes", { value }); - break; - case "bitrate": - value = t("common.bitrate", { value }); - break; - case "date": - value = t("common.date", { - value, - lng: mapping?.locale, - dateStyle: mapping?.dateStyle ?? "long", - timeStyle: mapping?.timeStyle, - }); - break; - case "relativeDate": - value = t("common.relativeDate", { - value, - lng: mapping?.locale, - style: mapping?.style, - numeric: mapping?.numeric, - }); - break; - case "size": - value = t("common.number", { value: getSize(value) }); - break; - case "text": - default: - // nothing - } - - // Apply fixed prefix. - const prefix = mapping?.prefix; - if (prefix) { - value = `${prefix} ${value}`; - } - - // Apply fixed suffix. - const suffix = mapping?.suffix; - if (suffix) { - value = `${value} ${suffix}`; - } - - 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(); diff --git a/src/widgets/customapi/utils.js b/src/widgets/customapi/utils.js new file mode 100644 index 000000000..42ed36b68 --- /dev/null +++ b/src/widgets/customapi/utils.js @@ -0,0 +1,151 @@ +import * as shvl from "utils/config/shvl"; + +export function getValue(field, data) { + let value = data; + let lastField = field; + let key = ""; + + // Support APIs that return arrays or scalars directly. + if (typeof field === "undefined") { + return value; + } + + // shvl is easier, everything else is kept for backwards compatibility. + if (typeof field === "string") { + return shvl.get(data, field, null) ?? data[field] ?? null; + } + + while (typeof lastField === "object") { + key = Object.keys(lastField)[0] ?? null; + + if (key === null) { + break; + } + + value = value[key]; + lastField = lastField[key]; + } + + if (typeof value === "undefined") { + return null; + } + + return value[lastField] ?? null; +} + +export function getSize(data) { + if (Array.isArray(data) || typeof data === "string") { + return data.length; + } else if (typeof data === "object" && data !== null) { + return Object.keys(data).length; + } + + return NaN; +} + +export function formatValue(t, mapping, rawValue) { + let value = rawValue; + + // Remap the value. + const remaps = mapping?.remap ?? []; + for (let i = 0; i < remaps.length; i += 1) { + const remap = remaps[i]; + if (remap?.any || remap?.value === value) { + value = remap.to; + break; + } + } + + // Scale the value. Accepts either a number to multiply by or a string + // like "12/345". + const scale = mapping?.scale; + if (typeof scale === "number") { + value *= scale; + } else if (typeof scale === "string") { + const parts = scale.split("/"); + const numerator = parts[0] ? parseFloat(parts[0]) : 1; + const denominator = parts[1] ? parseFloat(parts[1]) : 1; + value = (value * numerator) / denominator; + } + + // Format the value using a known type. + switch (mapping?.format) { + case "number": + value = t("common.number", { value: parseInt(value, 10) }); + break; + case "float": + value = t("common.number", { value }); + break; + case "percent": + value = t("common.percent", { value }); + break; + case "duration": + value = t("common.duration", { value }); + break; + case "bytes": + value = t("common.bytes", { value }); + break; + case "bitrate": + value = t("common.bitrate", { value }); + break; + case "date": + value = t("common.date", { + value, + lng: mapping?.locale, + dateStyle: mapping?.dateStyle ?? "long", + timeStyle: mapping?.timeStyle, + }); + break; + case "relativeDate": + value = t("common.relativeDate", { + value, + lng: mapping?.locale, + style: mapping?.style, + numeric: mapping?.numeric, + }); + break; + case "size": + value = t("common.number", { value: getSize(value) }); + break; + case "text": + default: + // nothing + } + + // Apply fixed prefix. + const prefix = mapping?.prefix; + if (prefix) { + value = `${prefix} ${value}`; + } + + // Apply fixed suffix. + const suffix = mapping?.suffix; + if (suffix) { + value = `${value} ${suffix}`; + } + + return value; +} + +export 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 ""; + } +}