sadpandajoe commented on code in PR #37794:
URL: https://github.com/apache/superset/pull/37794#discussion_r3827718798


##########
superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:
##########
@@ -125,455 +100,167 @@ function BigNumberVis({
     const { metricName, width } = props;
     if (!showMetricName || !metricName) return null;
 
-    const text = metricName;
-
     const container = createTemporaryContainer();
     document.body.append(container);
+
     const fontSize = computeMaxFontSize({
-      text,
+      text: metricName,
       maxWidth: width,
       maxHeight,
       className: 'metric-name',
       container,
     });
+
     container.remove();
 
     return (
-      <div
-        ref={metricNameRef}
-        className="metric-name"
-        style={{
-          fontSize,
-          height: 'auto',
-        }}
-      >
-        {text}
+      <div ref={metricNameRef} className="metric-name" style={{ fontSize }}>
+        {metricName}
       </div>
     );
   };
 
   const renderKicker = (maxHeight: number) => {
     const { timestamp, width } = props;
-    if (
-      !formatTime ||
-      !showTimestamp ||
-      typeof timestamp === 'string' ||
-      typeof timestamp === 'bigint' ||
-      typeof timestamp === 'boolean'
-    )
-      return null;
+    if (!formatTime || !showTimestamp || timestamp == null) return null;
 
-    const text = timestamp === null ? '' : formatTime(timestamp);
+    const text = formatTime(timestamp as number | Date);
 
     const container = createTemporaryContainer();
     document.body.append(container);
+
     const fontSize = computeMaxFontSize({
       text,
       maxWidth: width,
       maxHeight,
       className: 'kicker',
       container,
     });
+
     container.remove();
 
     return (
-      <div
-        ref={kickerRef}
-        className="kicker"
-        style={{
-          fontSize,
-          height: 'auto',
-        }}
-      >
+      <div ref={kickerRef} className="kicker" style={{ fontSize }}>
         {text}
       </div>
     );
   };
 
   const renderHeader = (maxHeight: number) => {
-    const { bigNumber, width, colorThresholdFormatters, onContextMenu } = 
props;
-    // Format bigNumber based on its type: null/undefined -> "No data", number 
-> format, else -> string
-    let text: string;
-    if (bigNumber === null || bigNumber === undefined) {
-      text = t('No data');
-    } else if (typeof bigNumber === 'number') {
-      text = headerFormatter(bigNumber);
-    } else {
-      // For string/boolean/Date values, convert to number if possible, else 
show as string
-      const numValue = Number(bigNumber);
-      text = Number.isNaN(numValue)
-        ? String(bigNumber)
-        : headerFormatter(numValue);
-    }
+    const { bigNumber, width } = props;
 
-    const hasThresholdColorFormatter =
-      Array.isArray(colorThresholdFormatters) &&
-      colorThresholdFormatters.length > 0;
-
-    let numberColor;
-    if (hasThresholdColorFormatter) {
-      colorThresholdFormatters!.forEach(formatter => {
-        const formatterResult = bigNumber
-          ? formatter.getColorFromValue(bigNumber as number)
-          : false;
-        if (formatterResult) {
-          numberColor = formatterResult;
-        }
-      });
-    } else {
-      numberColor = theme.colorText;
-    }
+    const text =
+      bigNumber == null
+        ? t('No data')
+        : typeof bigNumber === 'number'
+        ? headerFormatter(bigNumber)
+        : String(bigNumber);
 
     const container = createTemporaryContainer();
     document.body.append(container);
+
     const fontSize = computeMaxFontSize({
       text,
-      maxWidth: width * 0.9, // reduced it's max width
+      maxWidth: width * 0.9,
       maxHeight,
       className: 'header-line',
       container,
     });
-    container.remove();
 
-    const handleContextMenu = (e: MouseEvent<HTMLDivElement>) => {
-      if (onContextMenu) {
-        e.preventDefault();
-        onContextMenu(e.nativeEvent.clientX, e.nativeEvent.clientY);
-      }
-    };
+    container.remove();
 
     return (
-      <div
-        ref={headerRef}
-        className="header-line"
-        style={{
-          display: 'flex',
-          alignItems: 'center',
-          fontSize,
-          height: 'auto',
-          color: numberColor,
-        }}
-        onContextMenu={handleContextMenu}
-      >
+      <div ref={headerRef} className="header-line" style={{ fontSize }}>

Review Comment:
   The refactor still receives `colorThresholdFormatters` from Big Number 
Total, but the header no longer reads them, so conditional-formatting rules no 
longer color the displayed value. Could this restore the threshold-color 
selection on the header?



##########
superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts:
##########
@@ -105,306 +90,101 @@ export default function transformProps(
     startYAxisAtZero,
     subheader = '',
     subheaderFontSize,
-    forceTimestampFormatting,
-    yAxisFormat,
-    currencyFormat,
-    timeRangeFixed,
-    showXAxis = false,
-    showXAxisMinMaxLabels = false,
-    showYAxis = false,
-    showYAxisMinMaxLabels = false,
+    alignment = 'center',
   } = formData;
-  const granularity = extractTimegrain(rawFormData);
-  const {
-    data = [],
-    colnames = [],
-    coltypes = [],
-    from_dttm: fromDatetime,
-    to_dttm: toDatetime,
-    detected_currency: detectedCurrency,
-  } = queriesData[0];
-
-  const aggregatedQueryData = queriesData.length > 1 ? queriesData[1] : null;
-
-  const hasAggregatedData =
-    aggregatedQueryData?.data &&
-    aggregatedQueryData.data.length > 0 &&
-    aggregation !== 'LAST_VALUE';
 
-  const aggregatedData = hasAggregatedData ? aggregatedQueryData.data[0] : 
null;
+  const { data = [], colnames = [], coltypes = [] } = queriesData[0];
   const refs: Refs = {};
-  const metricName = getMetricLabel(metric);
-  const metrics = chartProps.datasource?.metrics || [];
-  const originalLabel = getOriginalLabel(metric, metrics);
-  const showMetricName = chartProps.rawFormData?.show_metric_name ?? false;
-  const compareLag = Number(compareLag_) || 0;
-  let formattedSubheader = subheader;
 
-  const { r, g, b } = colorPicker;
-  const mainColor = `rgb(${r}, ${g}, ${b})`;
+  const metricName = getMetricLabel(metric);
+  const originalLabel = getOriginalLabel(metric, datasource?.metrics || []);
+  const showMetricName = rawFormData?.show_metric_name ?? false;
 
   const xAxisLabel = getXAxisLabel(rawFormData) as string;
-  let trendLineData: TimeSeriesDatum[] | undefined;
-  let percentChange = 0;
-  let bigNumber = data.length === 0 ? null : data[0][metricName];
-  let timestamp = data.length === 0 ? null : data[0][xAxisLabel];
-  let bigNumberFallback = null;
   let sortedData: [number | null, number | null][] = [];
 
-  if (data.length > 0) {
+  if (data.length) {
     sortedData = (data as BigNumberDatum[])
       .map(
         d =>
-          [d[xAxisLabel], parseMetricValue(d[metricName])] as [
+          [d[xAxisLabel] as number | null, parseMetricValue(d[metricName])] as 
[
             number | null,
             number | null,
           ],
       )
-      // sort in time descending order
       .sort((a, b) => (a[0] !== null && b[0] !== null ? b[0] - a[0] : 0));
   }
-  if (sortedData.length > 0) {
-    timestamp = sortedData[0][0];
 
-    // Raw aggregation uses server-side data, all others use client-side
-    if (aggregation === 'raw' && hasAggregatedData && aggregatedData) {
-      // Use server-side aggregation for raw
-      if (
-        aggregatedData[metricName] !== null &&
-        aggregatedData[metricName] !== undefined
-      ) {
-        bigNumber = aggregatedData[metricName];
-      } else {
-        const metricKeys = Object.keys(aggregatedData).filter(
-          key =>
-            key !== xAxisLabel &&
-            aggregatedData[key] !== null &&
-            typeof aggregatedData[key] === 'number',
-        );
-        bigNumber =
-          metricKeys.length > 0 ? aggregatedData[metricKeys[0]] : null;
-      }
-    } else {
-      // Use client-side aggregation for all other methods
-      bigNumber = computeClientSideAggregation(sortedData, aggregation);
-    }
+  let bigNumber = computeClientSideAggregation(sortedData, aggregation);
+  let timestamp = sortedData[0]?.[0] ?? null;
 
-    // Handle null bigNumber case
-    if (bigNumber === null) {
-      bigNumberFallback = sortedData.find(d => d[1] !== null);
-      bigNumber = bigNumberFallback ? bigNumberFallback[1] : null;
-      timestamp = bigNumberFallback ? bigNumberFallback[0] : null;
-    }
-  }
+  let formattedSubheader = subheader;
 
-  if (compareLag > 0 && sortedData.length > 0) {
-    const compareIndex = compareLag;
-    if (compareIndex < sortedData.length) {
-      const compareFromValue = sortedData[compareIndex][1];
-      const compareToValue = sortedData[0][1];
-      // compare values must both be non-nulls
-      if (compareToValue !== null && compareFromValue !== null) {
-        percentChange = compareFromValue
-          ? (Number(compareToValue) - compareFromValue) /
-            Math.abs(compareFromValue)
-          : 0;
-        formattedSubheader = `${formatPercentChange(
-          percentChange,
-        )} ${compareSuffix}`;
-      }
-    }
-  }
+  if (compareLag && sortedData.length > compareLag) {
+    const prev = sortedData[compareLag][1];
+    const curr = sortedData[0][1];
 
-  if (data.length > 0 && showTrendLine) {
-    // Filter out entries with null timestamps and reverse for chronological 
order
-    // TimeSeriesDatum requires [number, number | null] - timestamp must be 
non-null
-    const validData = sortedData.filter(
-      (d): d is [number, number | null] => d[0] !== null,
-    );
-    trendLineData = [...validData].reverse();
+    if (prev != null && curr != null && prev !== 0) {
+      formattedSubheader = `${formatPercentChange(
+        (curr - prev) / Math.abs(prev),
+      )} ${compareSuffix}`;
+    }
   }
 
-  let className = '';
-  if (percentChange > 0) {
-    className = 'positive';
-  } else if (percentChange < 0) {
-    className = 'negative';
+  let trendLineData: TimeSeriesDatum[] | undefined;
+  if (showTrendLine) {
+    trendLineData = [...sortedData].reverse();
   }
 
-  const metricColtypeIndex = colnames.findIndex(name => name === metricName);
-  const metricColtype =
-    metricColtypeIndex > -1 ? coltypes[metricColtypeIndex] : null;
+  const metricColtype = coltypes[colnames.findIndex(c => c === metricName)];
 
-  let metricEntry: Metric | undefined;
-  if (chartProps.datasource?.metrics) {
-    metricEntry = chartProps.datasource.metrics.find(
-      metricEntry => metricEntry.metric_name === metric,
-    );
-  }
+  const metricEntry: Metric | undefined = datasource?.metrics?.find(
+    m => m.metric_name === metric,
+  );
 
   const formatTime = getDateFormatter(
     timeFormat,
-    granularity,
+    extractTimegrain(rawFormData),
     metricEntry?.d3format,
   );
 
-  if (trendLineData && timeRangeFixed && fromDatetime) {
-    const toDatetimeOrToday = toDatetime ?? Date.now();
-    if (!trendLineData[0][0] || trendLineData[0][0] > fromDatetime) {
-      trendLineData.unshift([fromDatetime, null]);
-    }
-    if (
-      !trendLineData[trendLineData.length - 1][0] ||
-      trendLineData[trendLineData.length - 1][0]! < toDatetimeOrToday
-    ) {
-      trendLineData.push([toDatetimeOrToday, null]);
-    }
-  }
-
   const numberFormatter = getValueFormatter(
     metric,
-    currencyFormats,
-    columnFormats,
-    metricEntry?.d3format || yAxisFormat,
-    currencyFormat,
-    undefined,
-    data,
-    currencyCodeColumn,
-    detectedCurrency,
+    datasource?.currencyFormats,
+    datasource?.columnFormats,
+    metricEntry?.d3format,
   );
-  const xAxisFormatter = getXAxisFormatter(timeFormat);
-  const yAxisFormatter =
-    metricColtype === GenericDataType.Temporal ||
-    metricColtype === GenericDataType.String ||
-    forceTimestampFormatting
-      ? formatTime
-      : numberFormatter;
 
-  const echartOptions: EChartsCoreOption = trendLineData
-    ? {
-        series: [
-          {
-            data: trendLineData,
-            type: 'line',
-            smooth: true,
-            symbol: 'circle',
-            symbolSize: 10,
-            showSymbol: false,
-            color: mainColor,
-            areaStyle: {
-              color: new graphic.LinearGradient(0, 0, 0, 1, [
-                {
-                  offset: 0,
-                  color: mainColor,
-                },
-                {
-                  offset: 1,
-                  color: theme.colorBgContainer,
-                },
-              ]),
-            },
-          },
-        ],
-        xAxis: {
-          type: 'time',
-          show: showXAxis,
-          splitLine: {
-            show: false,
-          },
-          axisLabel: {
-            hideOverlap: true,
-            formatter: xAxisFormatter,
-            alignMinLabel: 'left',
-            alignMaxLabel: 'right',
-            showMinLabel: showXAxisMinMaxLabels,
-            showMaxLabel: showXAxisMinMaxLabels,
-          },
-        },
-        yAxis: {
-          type: 'value',
-          show: showYAxis,
-          scale: !startYAxisAtZero,
-          splitLine: {
-            show: false,
-          },
-          axisLabel: {
-            hideOverlap: true,
-            formatter: yAxisFormatter,
-            showMinLabel: showYAxisMinMaxLabels,
-            showMaxLabel: showYAxisMinMaxLabels,
-          },
-        },
-        grid:
-          showXAxis || showYAxis
-            ? {
-                containLabel: true,
-                bottom: TIMESERIES_CONSTANTS.gridOffsetBottom,
-                left: TIMESERIES_CONSTANTS.gridOffsetLeft,
-                right: TIMESERIES_CONSTANTS.gridOffsetRight,
-                top: TIMESERIES_CONSTANTS.gridOffsetTop,
-              }
-            : {
-                bottom: 0,
-                left: 0,
-                right: 0,
-                top: 0,
-              },
-        tooltip: {
-          ...getDefaultTooltip(refs),
-          show: !inContextMenu,
-          trigger: 'axis',
-          formatter: (params: { data: TimeSeriesDatum }[]) =>
-            tooltipHtml(
-              [
-                [
-                  metricName,
-                  params[0].data[1] === null
-                    ? t('N/A')
-                    : yAxisFormatter.format(params[0].data[1]),
-                ],
-              ],
-              formatTime(params[0].data[0]),
-            ),
-        },
-        aria: {
-          enabled: true,
-          label: {
-            description: `Big number visualization ${subheader}`,
-          },
-        },
-        useUTC: true,
-      }
-    : {};
+  const headerFormatter =
+    metricColtype === GenericDataType.Temporal ? formatTime : numberFormatter;

Review Comment:
   Agreed—the trendline transform no longer carries `forceTimestampFormatting` 
or the string-column case into `headerFormatter`, even though the control and 
added test cover that contract. Could this keep the previous formatter 
condition so forced date formatting still works?



##########
superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/transformProps.ts:
##########
@@ -105,306 +90,101 @@ export default function transformProps(
     startYAxisAtZero,
     subheader = '',
     subheaderFontSize,
-    forceTimestampFormatting,
-    yAxisFormat,
-    currencyFormat,
-    timeRangeFixed,
-    showXAxis = false,
-    showXAxisMinMaxLabels = false,
-    showYAxis = false,
-    showYAxisMinMaxLabels = false,
+    alignment = 'center',
   } = formData;
-  const granularity = extractTimegrain(rawFormData);
-  const {
-    data = [],
-    colnames = [],
-    coltypes = [],
-    from_dttm: fromDatetime,
-    to_dttm: toDatetime,
-    detected_currency: detectedCurrency,
-  } = queriesData[0];
-
-  const aggregatedQueryData = queriesData.length > 1 ? queriesData[1] : null;
-
-  const hasAggregatedData =
-    aggregatedQueryData?.data &&
-    aggregatedQueryData.data.length > 0 &&
-    aggregation !== 'LAST_VALUE';
 
-  const aggregatedData = hasAggregatedData ? aggregatedQueryData.data[0] : 
null;
+  const { data = [], colnames = [], coltypes = [] } = queriesData[0];
   const refs: Refs = {};
-  const metricName = getMetricLabel(metric);
-  const metrics = chartProps.datasource?.metrics || [];
-  const originalLabel = getOriginalLabel(metric, metrics);
-  const showMetricName = chartProps.rawFormData?.show_metric_name ?? false;
-  const compareLag = Number(compareLag_) || 0;
-  let formattedSubheader = subheader;
 
-  const { r, g, b } = colorPicker;
-  const mainColor = `rgb(${r}, ${g}, ${b})`;
+  const metricName = getMetricLabel(metric);
+  const originalLabel = getOriginalLabel(metric, datasource?.metrics || []);
+  const showMetricName = rawFormData?.show_metric_name ?? false;
 
   const xAxisLabel = getXAxisLabel(rawFormData) as string;
-  let trendLineData: TimeSeriesDatum[] | undefined;
-  let percentChange = 0;
-  let bigNumber = data.length === 0 ? null : data[0][metricName];
-  let timestamp = data.length === 0 ? null : data[0][xAxisLabel];
-  let bigNumberFallback = null;
   let sortedData: [number | null, number | null][] = [];
 
-  if (data.length > 0) {
+  if (data.length) {
     sortedData = (data as BigNumberDatum[])
       .map(
         d =>
-          [d[xAxisLabel], parseMetricValue(d[metricName])] as [
+          [d[xAxisLabel] as number | null, parseMetricValue(d[metricName])] as 
[
             number | null,
             number | null,
           ],
       )
-      // sort in time descending order
       .sort((a, b) => (a[0] !== null && b[0] !== null ? b[0] - a[0] : 0));
   }
-  if (sortedData.length > 0) {
-    timestamp = sortedData[0][0];
 
-    // Raw aggregation uses server-side data, all others use client-side
-    if (aggregation === 'raw' && hasAggregatedData && aggregatedData) {
-      // Use server-side aggregation for raw
-      if (
-        aggregatedData[metricName] !== null &&
-        aggregatedData[metricName] !== undefined
-      ) {
-        bigNumber = aggregatedData[metricName];
-      } else {
-        const metricKeys = Object.keys(aggregatedData).filter(
-          key =>
-            key !== xAxisLabel &&
-            aggregatedData[key] !== null &&
-            typeof aggregatedData[key] === 'number',
-        );
-        bigNumber =
-          metricKeys.length > 0 ? aggregatedData[metricKeys[0]] : null;
-      }
-    } else {
-      // Use client-side aggregation for all other methods
-      bigNumber = computeClientSideAggregation(sortedData, aggregation);
-    }
+  let bigNumber = computeClientSideAggregation(sortedData, aggregation);
+  let timestamp = sortedData[0]?.[0] ?? null;
 
-    // Handle null bigNumber case
-    if (bigNumber === null) {
-      bigNumberFallback = sortedData.find(d => d[1] !== null);
-      bigNumber = bigNumberFallback ? bigNumberFallback[1] : null;
-      timestamp = bigNumberFallback ? bigNumberFallback[0] : null;
-    }
-  }
+  let formattedSubheader = subheader;
 
-  if (compareLag > 0 && sortedData.length > 0) {
-    const compareIndex = compareLag;
-    if (compareIndex < sortedData.length) {
-      const compareFromValue = sortedData[compareIndex][1];
-      const compareToValue = sortedData[0][1];
-      // compare values must both be non-nulls
-      if (compareToValue !== null && compareFromValue !== null) {
-        percentChange = compareFromValue
-          ? (Number(compareToValue) - compareFromValue) /
-            Math.abs(compareFromValue)
-          : 0;
-        formattedSubheader = `${formatPercentChange(
-          percentChange,
-        )} ${compareSuffix}`;
-      }
-    }
-  }
+  if (compareLag && sortedData.length > compareLag) {
+    const prev = sortedData[compareLag][1];
+    const curr = sortedData[0][1];
 
-  if (data.length > 0 && showTrendLine) {
-    // Filter out entries with null timestamps and reverse for chronological 
order
-    // TimeSeriesDatum requires [number, number | null] - timestamp must be 
non-null
-    const validData = sortedData.filter(
-      (d): d is [number, number | null] => d[0] !== null,
-    );
-    trendLineData = [...validData].reverse();
+    if (prev != null && curr != null && prev !== 0) {
+      formattedSubheader = `${formatPercentChange(
+        (curr - prev) / Math.abs(prev),
+      )} ${compareSuffix}`;
+    }
   }
 
-  let className = '';
-  if (percentChange > 0) {
-    className = 'positive';
-  } else if (percentChange < 0) {
-    className = 'negative';
+  let trendLineData: TimeSeriesDatum[] | undefined;
+  if (showTrendLine) {
+    trendLineData = [...sortedData].reverse();
   }
 
-  const metricColtypeIndex = colnames.findIndex(name => name === metricName);
-  const metricColtype =
-    metricColtypeIndex > -1 ? coltypes[metricColtypeIndex] : null;
+  const metricColtype = coltypes[colnames.findIndex(c => c === metricName)];
 
-  let metricEntry: Metric | undefined;
-  if (chartProps.datasource?.metrics) {
-    metricEntry = chartProps.datasource.metrics.find(
-      metricEntry => metricEntry.metric_name === metric,
-    );
-  }
+  const metricEntry: Metric | undefined = datasource?.metrics?.find(
+    m => m.metric_name === metric,
+  );
 
   const formatTime = getDateFormatter(
     timeFormat,
-    granularity,
+    extractTimegrain(rawFormData),
     metricEntry?.d3format,
   );
 
-  if (trendLineData && timeRangeFixed && fromDatetime) {
-    const toDatetimeOrToday = toDatetime ?? Date.now();
-    if (!trendLineData[0][0] || trendLineData[0][0] > fromDatetime) {
-      trendLineData.unshift([fromDatetime, null]);
-    }
-    if (
-      !trendLineData[trendLineData.length - 1][0] ||
-      trendLineData[trendLineData.length - 1][0]! < toDatetimeOrToday
-    ) {
-      trendLineData.push([toDatetimeOrToday, null]);
-    }
-  }
-
   const numberFormatter = getValueFormatter(
     metric,
-    currencyFormats,
-    columnFormats,
-    metricEntry?.d3format || yAxisFormat,
-    currencyFormat,
-    undefined,
-    data,
-    currencyCodeColumn,
-    detectedCurrency,
+    datasource?.currencyFormats,
+    datasource?.columnFormats,
+    metricEntry?.d3format,
   );
-  const xAxisFormatter = getXAxisFormatter(timeFormat);
-  const yAxisFormatter =
-    metricColtype === GenericDataType.Temporal ||
-    metricColtype === GenericDataType.String ||
-    forceTimestampFormatting
-      ? formatTime
-      : numberFormatter;
 
-  const echartOptions: EChartsCoreOption = trendLineData
-    ? {
-        series: [
-          {
-            data: trendLineData,
-            type: 'line',
-            smooth: true,
-            symbol: 'circle',
-            symbolSize: 10,
-            showSymbol: false,
-            color: mainColor,
-            areaStyle: {
-              color: new graphic.LinearGradient(0, 0, 0, 1, [
-                {
-                  offset: 0,
-                  color: mainColor,
-                },
-                {
-                  offset: 1,
-                  color: theme.colorBgContainer,
-                },
-              ]),
-            },
-          },
-        ],
-        xAxis: {
-          type: 'time',
-          show: showXAxis,
-          splitLine: {
-            show: false,
-          },
-          axisLabel: {
-            hideOverlap: true,
-            formatter: xAxisFormatter,
-            alignMinLabel: 'left',
-            alignMaxLabel: 'right',
-            showMinLabel: showXAxisMinMaxLabels,
-            showMaxLabel: showXAxisMinMaxLabels,
-          },
-        },
-        yAxis: {
-          type: 'value',
-          show: showYAxis,
-          scale: !startYAxisAtZero,
-          splitLine: {
-            show: false,
-          },
-          axisLabel: {
-            hideOverlap: true,
-            formatter: yAxisFormatter,
-            showMinLabel: showYAxisMinMaxLabels,
-            showMaxLabel: showYAxisMinMaxLabels,
-          },
-        },
-        grid:
-          showXAxis || showYAxis
-            ? {
-                containLabel: true,
-                bottom: TIMESERIES_CONSTANTS.gridOffsetBottom,
-                left: TIMESERIES_CONSTANTS.gridOffsetLeft,
-                right: TIMESERIES_CONSTANTS.gridOffsetRight,
-                top: TIMESERIES_CONSTANTS.gridOffsetTop,
-              }
-            : {
-                bottom: 0,
-                left: 0,
-                right: 0,
-                top: 0,
-              },
-        tooltip: {
-          ...getDefaultTooltip(refs),
-          show: !inContextMenu,
-          trigger: 'axis',
-          formatter: (params: { data: TimeSeriesDatum }[]) =>
-            tooltipHtml(
-              [
-                [
-                  metricName,
-                  params[0].data[1] === null
-                    ? t('N/A')
-                    : yAxisFormatter.format(params[0].data[1]),
-                ],
-              ],
-              formatTime(params[0].data[0]),
-            ),
-        },
-        aria: {
-          enabled: true,
-          label: {
-            description: `Big number visualization ${subheader}`,
-          },
-        },
-        useUTC: true,
-      }
-    : {};
+  const headerFormatter =
+    metricColtype === GenericDataType.Temporal ? formatTime : numberFormatter;
 
-  const { onContextMenu } = hooks;
+  const echartOptions: EChartsCoreOption =
+    trendLineData && showTrendLine
+      ? { series: [{ type: 'line', data: trendLineData }] }
+      : {};

Review Comment:
   Agreed—the replacement option now contains only the series, so the existing 
axis visibility, min/max labels, grid offsets, and zero-baseline controls are 
not passed to ECharts. Could this retain those option mappings?



##########
superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberViz.tsx:
##########
@@ -125,455 +100,167 @@ function BigNumberVis({
     const { metricName, width } = props;
     if (!showMetricName || !metricName) return null;
 
-    const text = metricName;
-
     const container = createTemporaryContainer();
     document.body.append(container);
+
     const fontSize = computeMaxFontSize({
-      text,
+      text: metricName,
       maxWidth: width,
       maxHeight,
       className: 'metric-name',
       container,
     });
+
     container.remove();
 
     return (
-      <div
-        ref={metricNameRef}
-        className="metric-name"
-        style={{
-          fontSize,
-          height: 'auto',
-        }}
-      >
-        {text}
+      <div ref={metricNameRef} className="metric-name" style={{ fontSize }}>
+        {metricName}
       </div>
     );
   };
 
   const renderKicker = (maxHeight: number) => {
     const { timestamp, width } = props;
-    if (
-      !formatTime ||
-      !showTimestamp ||
-      typeof timestamp === 'string' ||
-      typeof timestamp === 'bigint' ||
-      typeof timestamp === 'boolean'
-    )
-      return null;
+    if (!formatTime || !showTimestamp || timestamp == null) return null;
 
-    const text = timestamp === null ? '' : formatTime(timestamp);
+    const text = formatTime(timestamp as number | Date);
 
     const container = createTemporaryContainer();
     document.body.append(container);
+
     const fontSize = computeMaxFontSize({
       text,
       maxWidth: width,
       maxHeight,
       className: 'kicker',
       container,
     });
+
     container.remove();
 
     return (
-      <div
-        ref={kickerRef}
-        className="kicker"
-        style={{
-          fontSize,
-          height: 'auto',
-        }}
-      >
+      <div ref={kickerRef} className="kicker" style={{ fontSize }}>
         {text}
       </div>
     );
   };
 
   const renderHeader = (maxHeight: number) => {
-    const { bigNumber, width, colorThresholdFormatters, onContextMenu } = 
props;
-    // Format bigNumber based on its type: null/undefined -> "No data", number 
-> format, else -> string
-    let text: string;
-    if (bigNumber === null || bigNumber === undefined) {
-      text = t('No data');
-    } else if (typeof bigNumber === 'number') {
-      text = headerFormatter(bigNumber);
-    } else {
-      // For string/boolean/Date values, convert to number if possible, else 
show as string
-      const numValue = Number(bigNumber);
-      text = Number.isNaN(numValue)
-        ? String(bigNumber)
-        : headerFormatter(numValue);
-    }
+    const { bigNumber, width } = props;
 
-    const hasThresholdColorFormatter =
-      Array.isArray(colorThresholdFormatters) &&
-      colorThresholdFormatters.length > 0;
-
-    let numberColor;
-    if (hasThresholdColorFormatter) {
-      colorThresholdFormatters!.forEach(formatter => {
-        const formatterResult = bigNumber
-          ? formatter.getColorFromValue(bigNumber as number)
-          : false;
-        if (formatterResult) {
-          numberColor = formatterResult;
-        }
-      });
-    } else {
-      numberColor = theme.colorText;
-    }
+    const text =
+      bigNumber == null
+        ? t('No data')
+        : typeof bigNumber === 'number'
+        ? headerFormatter(bigNumber)
+        : String(bigNumber);
 
     const container = createTemporaryContainer();
     document.body.append(container);
+
     const fontSize = computeMaxFontSize({
       text,
-      maxWidth: width * 0.9, // reduced it's max width
+      maxWidth: width * 0.9,
       maxHeight,
       className: 'header-line',
       container,
     });
-    container.remove();
 
-    const handleContextMenu = (e: MouseEvent<HTMLDivElement>) => {
-      if (onContextMenu) {
-        e.preventDefault();
-        onContextMenu(e.nativeEvent.clientX, e.nativeEvent.clientY);
-      }
-    };
+    container.remove();
 
     return (
-      <div
-        ref={headerRef}
-        className="header-line"
-        style={{
-          display: 'flex',
-          alignItems: 'center',
-          fontSize,
-          height: 'auto',
-          color: numberColor,
-        }}
-        onContextMenu={handleContextMenu}
-      >
+      <div ref={headerRef} className="header-line" style={{ fontSize }}>
         {text}
       </div>

Review Comment:
   Agreed—the transforms still supply `onContextMenu`, but the refactored 
header no longer calls it. This removes the metric-specific context menu path; 
could the header restore the prior handler?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to