Ver Fonte

create a re-usable file for format converter

namnguyen há 11 meses atrás
pai
commit
9b4b1a8391

+ 7 - 43
frontend/taipy-gui/src/components/Taipy/Metric.tsx

@@ -14,6 +14,7 @@
 import React, {CSSProperties, lazy, Suspense, useMemo} from 'react';
 import {Data} from "plotly.js";
 import {useClassNames, useDynamicJsonProperty, useDynamicProperty} from "../../utils/hooks";
+import {extractPrefix, extractSuffix, extractFormatSpecifier} from "../../utils/formatConversion";
 import {TaipyBaseProps, TaipyHoverProps} from "./utils";
 import Box from "@mui/material/Box";
 import Skeleton from "@mui/material/Skeleton";
@@ -44,8 +45,6 @@ interface MetricProps extends TaipyBaseProps, TaipyHoverProps {
 
 const emptyLayout = {} as Record<string, Record<string, unknown>>;
 const defaultStyle = {position: "relative", display: "inline-block"};
-const FORMAT_MATCH_REGEX = /(?<=[bdieufgosxX])./;
-const FORMAT_REPLACE_REGEX = /%([0-9]*)([.][0-9]+)?([bdieufgosxX])/g;
 
 const Metric = (props: MetricProps) => {
     const {
@@ -61,43 +60,6 @@ const Metric = (props: MetricProps) => {
     const baseStyle = useDynamicJsonProperty(props.style, props.defaultStyle || "", defaultStyle);
 
     const data = useMemo(() => {
-        const sprintfToD3Converter = (format: string) => {
-            return format?.replace(FORMAT_REPLACE_REGEX, (match, width, precision, type) => {
-                switch (type) {
-                    case "b":
-                        return "b";
-                    case "d":
-                        return "d";
-                    case "i":
-                        return "d";
-                    case "e":
-                        return "e";
-                    case "f":
-                        return "." + (precision?.slice(1) ?? "2") + "f";
-                    case "g":
-                        return "." + (precision?.slice(1) ?? "2") + "g";
-                    case "o":
-                        return "o";
-                    case "s":
-                        return "";
-                    case "x":
-                        return "x";
-                    case "X":
-                        return "X";
-                    default:
-                        return "";
-                }
-            });
-        }
-
-        const finalFormat = (input: string) => {
-            const regex = /([bdieufgosxX]).*/g;
-            return input ? input.replace(regex, '$1') : undefined;
-        }
-
-        const formattedNumberValue = props.format ? finalFormat(sprintfToD3Converter(props.format)) : undefined;
-        const formattedDeltaValue = props.formatDelta ? finalFormat(sprintfToD3Converter(props.formatDelta)) : undefined;
-
         return [
             {
                 domain: {x: [0, 1], y: [0, 1]},
@@ -105,13 +67,15 @@ const Metric = (props: MetricProps) => {
                 type: "indicator",
                 mode: "gauge" + (showValue ? "+number" : "") + (delta !== undefined ? "+delta" : ""),
                 number: {
-                    suffix: props.format?.match(FORMAT_MATCH_REGEX)?.[0] ?? "",
-                    valueformat: formattedNumberValue,
+                    prefix: extractPrefix(props.format),
+                    suffix: extractSuffix(props.format),
+                    valueformat: extractFormatSpecifier(props.format),
                 },
                 delta: {
                     reference: typeof value === 'number' && typeof delta === 'number' ? value - delta : undefined,
-                    suffix: props.formatDelta?.match(FORMAT_MATCH_REGEX)?.[0] ?? "",
-                    valueformat: formattedDeltaValue
+                    prefix: extractPrefix(props.formatDelta),
+                    suffix: extractSuffix(props.formatDelta),
+                    valueformat: extractFormatSpecifier(props.formatDelta)
                 },
                 gauge: {
                     axis: {

+ 119 - 0
frontend/taipy-gui/src/utils/formatConversion.ts

@@ -0,0 +1,119 @@
+/*
+ * Copyright 2021-2024 Avaiga Private Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+const FORMAT_REPLACE_REGEX = /%([0-9]*)([.][0-9]+)?([bdieufgosxX])/g;
+
+/**
+ * Converts a sprintf format string to a D3 format string.
+ *
+ * This function takes a sprintf format string as input and returns a D3 format string.
+ * The conversion is done by replacing each sprintf format specifier with the corresponding D3 format specifier.
+ * If the input format string is undefined, the function returns undefined.
+ * If an error occurs during the conversion, the function logs the error to the console and returns undefined.
+ *
+ * @param format - The sprintf format string to convert.
+ * @returns The converted D3 format string, or undefined if the input is undefined or if an error occurs.
+ */
+const sprintfToD3Converter = (format: string) => {
+    try {
+        return format?.replace(FORMAT_REPLACE_REGEX, (match, width, precision, type) => {
+            switch (type) {
+                case "b":
+                    return "b";
+                case "d":
+                    return "d";
+                case "i":
+                    return "d";
+                case "e":
+                    return "e";
+                case "f":
+                    return "." + (precision?.slice(1) ?? "2") + "f";
+                case "g":
+                    return "." + (precision?.slice(1) ?? "2") + "g";
+                case "o":
+                    return "o";
+                case "s":
+                    return "";
+                case "x":
+                    return "x";
+                case "X":
+                    return "X";
+                default:
+                    return "";
+            }
+        });
+    } catch (error) {
+        console.error(`Failed to convert format "${format}" to D3 format: ${error}`);
+        return undefined;
+    }
+}
+
+/**
+ * Extracts the prefix from the format string.
+ * @param format - The format string.
+ * @returns The extracted prefix, or undefined if the format is undefined.
+ */
+export const extractPrefix = (format: string | undefined): string | undefined => {
+    if (format === undefined) {
+        return undefined;
+    }
+
+    try {
+        const PREFIX_MATCH_REGEX: RegExp = /.*?(?=%)/;
+        return format.match(PREFIX_MATCH_REGEX)?.[0] ?? "";
+    } catch (error) {
+        console.error(`Failed to extract prefix from format "${format}": ${error}`);
+        return undefined;
+    }
+}
+
+/**
+ * Extracts the suffix from the format string.
+ * @param format - The format string.
+ * @returns The extracted suffix, or undefined if the format is undefined.
+ */
+export const extractSuffix = (format: string | undefined): string | undefined => {
+    if (format === undefined) {
+        return undefined;
+    }
+
+    try {
+        const SURFIX_MATCH_REGEX: RegExp = /(?<=[bdieufgosxX])./;
+        return format.match(SURFIX_MATCH_REGEX)?.[0] ?? "";
+    } catch (error) {
+        console.error(`Failed to extract suffix from format "${format}": ${error}`);
+        return undefined;
+    }
+}
+
+/**
+ * Extracts the format specifier from the input string.
+ * The input string is expected to be in sprintf format.
+ * The function returns the format specifier (one of 'b', 'd', 'i', 'e', 'f', 'g', 'o', 's', 'x', 'X') if it exists, or undefined otherwise.
+ * @param input - The input string in sprintf format.
+ * @returns The extracted format specifier, or undefined if no specifier is found or if the input is undefined.
+ */
+export const extractFormatSpecifier = (input: string | undefined): string | undefined => {
+    if (input === undefined) {
+        return undefined;
+    }
+
+    try {
+        const regex: RegExp = /.*%?([bdieufgosxX]).*/g;
+        const convertedInput = sprintfToD3Converter(input);
+        return convertedInput ? convertedInput.replace(regex, '$1') : undefined;
+    } catch (error) {
+        console.error(`Failed to extract format specifier from input "${input}": ${error}`);
+        return undefined;
+    }
+}