Files
superset2/superset-frontend/plugins/plugin-chart-ag-grid-table/src/renderers/NumericCellRenderer.tsx
Superset Dev 0e32b0399f chore(lint): upgrade no-unused-vars rule from warn to error
Flip @typescript-eslint/no-unused-vars from "warn" to "error" in
oxlint.json (with argsIgnorePattern/varsIgnorePattern of "^_" and
caughtErrors "none"), and clean up the resulting violations across the
frontend.

Fixes favor proper cleanup over underscore hacks: genuinely dead
imports, variables, and destructured props are removed; parameters are
only "_"-prefixed when their position is required by an external or
callback signature (event handlers, render props, antd validators,
forwardRef, or omit-from-rest destructuring).

Note: the .eslintrc.js half of the prior attempt (#37886) is obsolete
since the frontend migrated to oxlint as the primary linter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-16 15:48:06 -07:00

199 lines
5.2 KiB
TypeScript

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import { styled } from '@apache-superset/core/theme';
import { CustomCellRendererProps } from '@superset-ui/core/components/ThemedAgGridReact';
import { BasicColorFormatterType, InputColumn, ValueRange } from '../types';
const StyledTotalCell = styled.div`
${() => `
font-weight: bold;
`}
`;
const CellContainer = styled.div<{ backgroundColor?: string; align?: string }>`
display: flex;
background-color: ${({ backgroundColor }) =>
backgroundColor || 'transparent'};
justify-content: ${({ align }) => align || 'left'};
`;
const ArrowContainer = styled.div<{ arrowColor?: string }>`
margin-right: 10px;
color: ${({ arrowColor }) => arrowColor || 'inherit'};
`;
const Bar = styled.div<{
offset: number;
percentage: number;
background: string;
}>`
position: absolute;
left: ${({ offset }) => `${offset}%`};
top: 0;
height: 100%;
width: ${({ percentage }) => `${percentage}%`};
background-color: ${({ background }) => background};
z-index: 1;
`;
/**
* Cell background width calculation for horizontal bar chart
*/
function cellWidth({
value,
valueRange,
alignPositiveNegative,
}: {
value: number;
valueRange: [number, number];
alignPositiveNegative: boolean;
}) {
const [minValue, maxValue] = valueRange;
if (alignPositiveNegative) {
const perc = Math.abs(Math.round((value / maxValue) * 100));
return perc;
}
const posExtent = Math.abs(Math.max(maxValue, 0));
const negExtent = Math.abs(Math.min(minValue, 0));
const tot = posExtent + negExtent;
const perc2 = Math.round((Math.abs(value) / tot) * 100);
return perc2;
}
/**
* Cell left margin (offset) calculation for horizontal bar chart elements
* when alignPositiveNegative is not set
*/
function cellOffset({
value,
valueRange,
alignPositiveNegative,
}: {
value: number;
valueRange: [number, number];
alignPositiveNegative: boolean;
}) {
if (alignPositiveNegative) {
return 0;
}
const [minValue, maxValue] = valueRange;
const posExtent = Math.abs(Math.max(maxValue, 0));
const negExtent = Math.abs(Math.min(minValue, 0));
const tot = posExtent + negExtent;
return Math.round((Math.min(negExtent + value, negExtent) / tot) * 100);
}
/**
* Cell background color calculation for horizontal bar chart
*/
function cellBackground({
value,
colorPositiveNegative = false,
}: {
value: number;
colorPositiveNegative: boolean;
}) {
if (!colorPositiveNegative) {
return 'transparent'; // Use transparent background when colorPositiveNegative is false
}
const r = value < 0 ? 150 : 0;
const g = value >= 0 ? 150 : 0;
return `rgba(${r},${g},0,0.2)`;
}
export const NumericCellRenderer = (
params: CustomCellRendererProps & {
allowRenderHtml: boolean;
columns: InputColumn[];
hasBasicColorFormatters: boolean | undefined;
col: InputColumn;
basicColorFormatters: {
[Key: string]: BasicColorFormatterType;
}[];
valueRange: ValueRange;
alignPositiveNegative: boolean;
colorPositiveNegative: boolean;
},
) => {
const {
value,
valueFormatted,
node,
hasBasicColorFormatters,
col,
basicColorFormatters,
valueRange,
alignPositiveNegative,
colorPositiveNegative,
} = params;
if (node?.rowPinned === 'bottom') {
return <StyledTotalCell>{valueFormatted ?? value}</StyledTotalCell>;
}
let arrow = '';
let arrowColor = '';
if (hasBasicColorFormatters && col?.metricName) {
arrow =
basicColorFormatters?.[node?.rowIndex as number]?.[col.metricName]
?.mainArrow;
arrowColor =
basicColorFormatters?.[node?.rowIndex as number]?.[
col.metricName
]?.arrowColor?.toLowerCase();
}
const alignment =
col?.config?.horizontalAlign || (col?.isNumeric ? 'right' : 'left');
if (!valueRange) {
return (
<CellContainer align={alignment}>
{arrow && (
<ArrowContainer arrowColor={arrowColor}>{arrow}</ArrowContainer>
)}
<div>{valueFormatted ?? value}</div>
</CellContainer>
);
}
const CellWidth = cellWidth({
value: value as number,
valueRange,
alignPositiveNegative,
});
const CellOffset = cellOffset({
value: value as number,
valueRange,
alignPositiveNegative,
});
const background = cellBackground({
value: value as number,
colorPositiveNegative,
});
return (
<div>
<Bar offset={CellOffset} percentage={CellWidth} background={background} />
{valueFormatted ?? value}
</div>
);
};