EnxDev commented on code in PR #43820:
URL: https://github.com/apache/superset/pull/43820#discussion_r3933335482


##########
superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx:
##########
@@ -154,9 +269,158 @@ const renderOperator = ({
   );
 };
 
+const renderBoundFields = (
+  operator?: Comparator,
+  serverPagination?: boolean,
+) => {
+  const { showMin, showMax } = getBoundVisibility(operator);
+  if (!showMin && !showMax) {
+    return null;
+  }
+  // Cross-validate min/max only when both are shown; a lone bound
+  // validates against targetValue instead, its other end of the scale.
+  const useCrossFieldRules = showMin && showMax;
+  const minRules = useCrossFieldRules ? rulesMinBound : rulesMinBoundTarget;
+  const maxRules = useCrossFieldRules ? rulesMaxBound : rulesMaxBoundTarget;
+  const minDependencies = useCrossFieldRules ? minBoundDeps : targetValueDeps;
+  const maxDependencies = useCrossFieldRules ? maxBoundDeps : targetValueDeps;
+  // % of column derives its denominator from the loaded rows, which under
+  // server pagination is just the current page -- disable picking it there
+  // so the scale doesn't drift per page. Existing saved configs keep working.
+  const boundUnitSelectOptions = serverPagination

Review Comment:
   Good catch. This is addressed in 3ae2f00aa4. getColorFormatters now accepts 
a disablePercentBounds flag, and both Table and AG Grid pass serverPagination 
through to it. As a result, an already-saved percent rule is suppressed instead 
of being evaluated against the loaded page. The saved configuration remains 
visible and editable, and the tooltip explains why percent mode is unavailable 
under server pagination.



##########
superset-frontend/packages/superset-ui-chart-controls/src/utils/getColorFormatters.ts:
##########
@@ -83,17 +138,61 @@ export const getColorFunction = (
     targetValueRight,
     colorScheme,
     useGradient,
+    minBound: rawMinBound,
+    maxBound: rawMaxBound,
+    centerValue: rawCenterValue,
+    lowColor,
+    midColor,
+    highColor,
+    boundUnit,
+    percentDenominator,
   }: ConditionalFormattingConfig,
   columnValues: number[] | string[] | (boolean | null)[],
   alpha?: boolean,
 ) => {
+  const resolvePercentBound = (bound: number | undefined) => {
+    if (boundUnit !== BoundUnit.Percent || bound === undefined) {
+      return bound;
+    }
+    const numericColumnValues = (
+      columnValues as (number | string | boolean | null)[]
+    ).filter((value): value is number => typeof value === 'number');
+    if (numericColumnValues.length === 0) {
+      return undefined;
+    }
+    // Use the magnitude so a negative denominator doesn't flip the scale;
+    // a zero denominator falls back to unset rather than collapsing it.
+    const denominatorValue = Math.abs(

Review Comment:
   Agreed. Since the option is Column max, preserving the actual signed maximum 
is the least surprising behavior. Addressed in f8c9745dc3: Column sum still 
uses its magnitude, while Column max retains its sign. A regression test with 
[-100, -5] verifies that 100% resolves to -5, and the documentation makes the 
distinction explicit. This commit will appear on the PR after the next push.



##########
superset-frontend/packages/superset-ui-chart-controls/src/utils/getColorFormatters.ts:
##########
@@ -129,7 +239,10 @@ export const getColorFunction = (
         typeof targetValue === 'number' && value > targetValue!
           ? {
               cutoffValue: targetValue!,
-              extremeValue: Math.max(...allValues),
+              extremeValue:
+                maxBound !== undefined && maxBound > targetValue

Review Comment:
   The popover catches this for Value mode: > and >= require maxBound > 
targetValue, while < and <= require minBound < targetValue. In percent mode the 
direct comparison is intentionally skipped because the bound and target use 
different units until the column denominator is known. The formatter fallback 
remains as a defensive path for imported or API-provided configurations. The 
validation behavior is included in 3ae2f00aa4.



##########
superset-frontend/packages/superset-ui-chart-controls/src/utils/getColorFormatters.ts:
##########
@@ -72,6 +75,58 @@ export const getOpacity = (
   );
 };
 
+const parseColorToRgb = (color: RGBColor | string) => {
+  if (typeof color === 'string') {
+    const { r, g, b } = tinycolor(color).toRgb();
+    return { r, g, b };
+  }
+  return { r: color.r, g: color.g, b: color.b };
+};
+
+export const getDivergingColor = (
+  value: number,
+  cutoffValue: number,
+  centerValue: number,
+  extremeValue: number,
+  lowColor: RGBColor | string,
+  midColor: RGBColor | string,
+  highColor: RGBColor | string,
+): string => {
+  const clampedValue = Math.min(Math.max(value, cutoffValue), extremeValue);
+  const belowCenter = clampedValue <= centerValue;
+  const from = parseColorToRgb(belowCenter ? lowColor : midColor);
+  const to = parseColorToRgb(belowCenter ? midColor : highColor);
+  const rangeStart = belowCenter ? cutoffValue : centerValue;
+  const rangeEnd = belowCenter ? centerValue : extremeValue;
+  const ratio =
+    rangeEnd === rangeStart
+      ? 1
+      : (clampedValue - rangeStart) / (rangeEnd - rangeStart);
+  return rgbaToHex({
+    r: from.r + (to.r - from.r) * ratio,
+    g: from.g + (to.g - from.g) * ratio,
+    b: from.b + (to.b - from.b) * ratio,
+    a: 1,
+  });
+};
+
+const isValidDivergingConfig = (
+  centerValue: number | undefined,
+  lowColor: RGBColor | string | undefined,
+  midColor: RGBColor | string | undefined,
+  highColor: RGBColor | string | undefined,
+  cutoffValue: number | string,
+  extremeValue: number | string,
+): centerValue is number =>
+  centerValue !== undefined &&
+  lowColor !== undefined &&
+  midColor !== undefined &&
+  highColor !== undefined &&
+  typeof cutoffValue === 'number' &&
+  typeof extremeValue === 'number' &&
+  centerValue > cutoffValue &&
+  centerValue < extremeValue;

Review Comment:
   Confirmed that the popover surfaces this before submission. Its center 
validators use strict comparisons, so centerValue must be greater than minBound 
and smaller than maxBound; equality at either endpoint is rejected. The 
formatter fallback remains defensive for imported or API-provided invalid 
configurations.



##########
docs/docs/using-superset/creating-your-first-dashboard.mdx:
##########
@@ -328,6 +328,8 @@ Conditional formatting rules highlight cells based on their 
values. Rules can be
 
 Each rule has a **"Use gradient"** toggle: enabled applies a varying opacity 
(lighter = further from threshold), disabled applies a solid fill at full 
opacity regardless of value.
 
+For numeric rules, the optional **"Min bound"** / **"Max bound"** fields let 
you override the auto-detected color range with fixed values instead of relying 
on the minimum/maximum found in the data — useful when you want consistent 
coloring across dashboards or data refreshes.

Review Comment:
   Added in 3ae2f00aa4. The documentation now explains the diverging 
low/mid/high scale, how percent bounds use Column max or Column sum, and why 
percent mode is unavailable with server pagination.



-- 
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