mirror of
https://github.com/apache/superset.git
synced 2026-04-21 17:14:57 +00:00
feat(viz-type): Ag grid table plugin Integration (#33517)
Signed-off-by: hainenber <dotronghai96@gmail.com> Co-authored-by: Amaan Nawab <nelsondrew07@gmail.com> Co-authored-by: Levis Mbote <111055098+LevisNgigi@users.noreply.github.com> Co-authored-by: Enzo Martellucci <52219496+EnxDev@users.noreply.github.com> Co-authored-by: Paul Rhodes <withnale@users.noreply.github.com> Co-authored-by: Vitor Avila <96086495+Vitor-Avila@users.noreply.github.com> Co-authored-by: Đỗ Trọng Hải <41283691+hainenber@users.noreply.github.com> Co-authored-by: Michael S. Molina <70410625+michael-s-molina@users.noreply.github.com> Co-authored-by: Sam Firke <sfirke@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* 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 '@superset-ui/core';
|
||||
import { CustomCellRendererProps } from 'ag-grid-react';
|
||||
import { BasicColorFormatterType, InputColumn } from '../types';
|
||||
import { useIsDark } from '../utils/useTableTheme';
|
||||
|
||||
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;
|
||||
`;
|
||||
|
||||
type ValueRange = [number, number];
|
||||
|
||||
/**
|
||||
* Cell background width calculation for horizontal bar chart
|
||||
*/
|
||||
function cellWidth({
|
||||
value,
|
||||
valueRange,
|
||||
alignPositiveNegative,
|
||||
}: {
|
||||
value: number;
|
||||
valueRange: ValueRange;
|
||||
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: ValueRange;
|
||||
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,
|
||||
isDarkTheme = false,
|
||||
}: {
|
||||
value: number;
|
||||
colorPositiveNegative: boolean;
|
||||
isDarkTheme: boolean;
|
||||
}) {
|
||||
if (!colorPositiveNegative) {
|
||||
return isDarkTheme ? 'rgba(255,255,255,0.2)' : 'rgba(0,0,0,0.2)'; // transparent or neutral
|
||||
}
|
||||
|
||||
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: any;
|
||||
alignPositiveNegative: boolean;
|
||||
colorPositiveNegative: boolean;
|
||||
},
|
||||
) => {
|
||||
const {
|
||||
value,
|
||||
valueFormatted,
|
||||
node,
|
||||
hasBasicColorFormatters,
|
||||
col,
|
||||
basicColorFormatters,
|
||||
valueRange,
|
||||
alignPositiveNegative,
|
||||
colorPositiveNegative,
|
||||
} = params;
|
||||
|
||||
const isDarkTheme = useIsDark();
|
||||
|
||||
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,
|
||||
isDarkTheme,
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Bar offset={CellOffset} percentage={CellWidth} background={background} />
|
||||
{valueFormatted ?? value}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user