Merge pull request #4193 from influxdata/enhancements/refactor-tablegraph
Refactor table graph and multi grid to remove unused functionalitypull/4208/head
commit
ff2ce4f8d5
|
@ -91,10 +91,10 @@ const updateMaxWidths = (
|
|||
|
||||
const currentWidth = useTimeWidth
|
||||
? timeFormatWidth
|
||||
: calculateSize(colValue, {
|
||||
: calculateSize(colValue.toString().trim(), {
|
||||
font: isLabel ? '"Roboto"' : '"RobotoMono", monospace',
|
||||
fontSize: '13px',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '12px',
|
||||
fontWeight: '500',
|
||||
}).width + CELL_HORIZONTAL_PADDING
|
||||
|
||||
const {widths: Widths} = maxColumnWidths
|
||||
|
@ -151,6 +151,7 @@ export const calculateColumnWidths = (
|
|||
const timeFormatWidth = calculateTimeColumnWidth(
|
||||
timeFormat === '' ? DEFAULT_TIME_FORMAT : timeFormat
|
||||
)
|
||||
|
||||
return fastReduce<TimeSeriesValue[], ColumnWidths>(
|
||||
data,
|
||||
(acc: ColumnWidths, row: TimeSeriesValue[], r: number) => {
|
||||
|
|
|
@ -74,6 +74,7 @@ class Layout extends Component<Props> {
|
|||
) : (
|
||||
<RefreshingGraph
|
||||
onZoom={onZoom}
|
||||
timeFormat={cell.timeFormat}
|
||||
axes={cell.axes}
|
||||
type={cell.type}
|
||||
inView={cell.inView}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import * as React from 'react'
|
||||
import CellMeasurerCacheDecorator from './CellMeasurerCacheDecorator'
|
||||
import _ from 'lodash'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
import {Grid} from 'react-virtualized'
|
||||
import {Grid, AutoSizer} from 'react-virtualized'
|
||||
|
||||
const SCROLLBAR_SIZE_BUFFER = 20
|
||||
const ROW_HEIGHT = 30
|
||||
|
||||
type HeightWidthFunction = (arg: {index: number}) => number
|
||||
|
||||
export interface PropsMultiGrid {
|
||||
|
@ -14,24 +16,16 @@ export interface PropsMultiGrid {
|
|||
classNameBottomRightGrid?: string
|
||||
classNameTopLeftGrid?: string
|
||||
classNameTopRightGrid?: string
|
||||
enableFixedColumnScroll?: boolean
|
||||
enableFixedRowScroll?: boolean
|
||||
fixedColumnCount?: number
|
||||
fixedRowCount?: number
|
||||
style?: object
|
||||
styleBottomLeftGrid?: object
|
||||
styleBottomRightGrid?: object
|
||||
styleTopLeftGrid?: object
|
||||
styleTopRightGrid?: object
|
||||
scrollTop?: number
|
||||
scrollLeft?: number
|
||||
scrollToRow?: number
|
||||
scrollToColumn?: number
|
||||
rowCount?: number
|
||||
rowHeight?: number | HeightWidthFunction
|
||||
columnWidth?: number | HeightWidthFunction
|
||||
onScroll?: (arg: object) => {}
|
||||
onSectionRendered?: () => {}
|
||||
cellRenderer?: (arg: object) => JSX.Element
|
||||
[key: string]: any // MultiGrid can accept any prop, and will rerender if they change
|
||||
onMount?: (mg: MultiGrid) => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -42,83 +36,32 @@ interface State {
|
|||
showVerticalScrollbar: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders 1, 2, or 4 Grids depending on configuration.
|
||||
* A main (body) Grid will always be rendered.
|
||||
* Optionally, 1-2 Grids for sticky header rows will also be rendered.
|
||||
* If no sticky columns, only 1 sticky header Grid will be rendered.
|
||||
* If sticky columns, 2 sticky header Grids will be rendered.
|
||||
*/
|
||||
class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
||||
public static defaultProps = {
|
||||
classNameBottomLeftGrid: '',
|
||||
classNameBottomRightGrid: '',
|
||||
classNameTopLeftGrid: '',
|
||||
classNameTopRightGrid: '',
|
||||
enableFixedColumnScroll: false,
|
||||
enableFixedRowScroll: false,
|
||||
fixedColumnCount: 0,
|
||||
fixedRowCount: 0,
|
||||
scrollToColumn: -1,
|
||||
scrollToRow: -1,
|
||||
style: {},
|
||||
styleBottomLeftGrid: {},
|
||||
styleBottomRightGrid: {},
|
||||
styleTopLeftGrid: {},
|
||||
styleTopRightGrid: {},
|
||||
}
|
||||
|
||||
public static getDerivedStateFromProps(
|
||||
nextProps: PropsMultiGrid,
|
||||
prevState: State
|
||||
) {
|
||||
if (
|
||||
nextProps.scrollLeft !== prevState.scrollLeft ||
|
||||
nextProps.scrollTop !== prevState.scrollTop
|
||||
) {
|
||||
return {
|
||||
scrollLeft:
|
||||
nextProps.scrollLeft != null && nextProps.scrollLeft >= 0
|
||||
? nextProps.scrollLeft
|
||||
: prevState.scrollLeft,
|
||||
scrollTop:
|
||||
nextProps.scrollTop != null && nextProps.scrollTop >= 0
|
||||
? nextProps.scrollTop
|
||||
: prevState.scrollTop,
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private deferredInvalidateColumnIndex: number = 0
|
||||
private deferredInvalidateRowIndex: number = 0
|
||||
private bottomLeftGrid: Grid
|
||||
private bottomRightGrid: Grid
|
||||
private topLeftGrid: Grid
|
||||
private topRightGrid: Grid
|
||||
private deferredMeasurementCacheBottomLeftGrid: CellMeasurerCacheDecorator
|
||||
private deferredMeasurementCacheBottomRightGrid: CellMeasurerCacheDecorator
|
||||
private deferredMeasurementCacheTopRightGrid: CellMeasurerCacheDecorator
|
||||
private leftGridWidth: number | null = 0
|
||||
private topGridHeight: number | null = 0
|
||||
private lastRenderedColumnWidth: number | HeightWidthFunction
|
||||
private lastRenderedFixedColumnCount: number = 0
|
||||
private lastRenderedFixedRowCount: number = 0
|
||||
private lastRenderedRowHeight: number | HeightWidthFunction
|
||||
private bottomRightGridStyle: object | null
|
||||
private topRightGridStyle: object | null
|
||||
private lastRenderedStyle: object | null
|
||||
private lastRenderedHeight: number = 0
|
||||
private lastRenderedWidth: number = 0
|
||||
private containerTopStyle: object | null
|
||||
private containerBottomStyle: object | null
|
||||
private containerOuterStyle: object | null
|
||||
private lastRenderedStyleBottomLeftGrid: object | null
|
||||
private lastRenderedStyleBottomRightGrid: object | null
|
||||
private lastRenderedStyleTopLeftGrid: object | null
|
||||
private lastRenderedStyleTopRightGrid: object | null
|
||||
private bottomLeftGridStyle: object | null
|
||||
private topLeftGridStyle: object | null
|
||||
|
||||
constructor(props: PropsMultiGrid, context) {
|
||||
|
@ -131,82 +74,6 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
showHorizontalScrollbar: false,
|
||||
showVerticalScrollbar: false,
|
||||
}
|
||||
|
||||
const {deferredMeasurementCache, fixedColumnCount, fixedRowCount} = props
|
||||
|
||||
this.maybeCalculateCachedStyles(true)
|
||||
|
||||
if (deferredMeasurementCache) {
|
||||
this.deferredMeasurementCacheBottomLeftGrid =
|
||||
fixedRowCount > 0
|
||||
? new CellMeasurerCacheDecorator({
|
||||
cellMeasurerCache: deferredMeasurementCache,
|
||||
columnIndexOffset: 0,
|
||||
rowIndexOffset: fixedRowCount,
|
||||
})
|
||||
: deferredMeasurementCache
|
||||
|
||||
this.deferredMeasurementCacheBottomRightGrid =
|
||||
fixedColumnCount > 0 || fixedRowCount > 0
|
||||
? new CellMeasurerCacheDecorator({
|
||||
cellMeasurerCache: deferredMeasurementCache,
|
||||
columnIndexOffset: fixedColumnCount,
|
||||
rowIndexOffset: fixedRowCount,
|
||||
})
|
||||
: deferredMeasurementCache
|
||||
|
||||
this.deferredMeasurementCacheTopRightGrid =
|
||||
fixedColumnCount > 0
|
||||
? new CellMeasurerCacheDecorator({
|
||||
cellMeasurerCache: deferredMeasurementCache,
|
||||
columnIndexOffset: fixedColumnCount,
|
||||
rowIndexOffset: 0,
|
||||
})
|
||||
: deferredMeasurementCache
|
||||
}
|
||||
}
|
||||
|
||||
public forceUpdateGrids() {
|
||||
if (this.bottomLeftGrid) {
|
||||
this.bottomLeftGrid.forceUpdate()
|
||||
}
|
||||
if (this.bottomRightGrid) {
|
||||
this.bottomRightGrid.forceUpdate()
|
||||
}
|
||||
if (this.topLeftGrid) {
|
||||
this.topLeftGrid.forceUpdate()
|
||||
}
|
||||
if (this.topRightGrid) {
|
||||
this.topRightGrid.forceUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
/** See Grid#invalidateCellSizeAfterRender */
|
||||
public invalidateCellSizeAfterRender({columnIndex = 0, rowIndex = 0} = {}) {
|
||||
this.deferredInvalidateColumnIndex =
|
||||
typeof this.deferredInvalidateColumnIndex === 'number'
|
||||
? Math.min(this.deferredInvalidateColumnIndex, columnIndex)
|
||||
: columnIndex
|
||||
this.deferredInvalidateRowIndex =
|
||||
typeof this.deferredInvalidateRowIndex === 'number'
|
||||
? Math.min(this.deferredInvalidateRowIndex, rowIndex)
|
||||
: rowIndex
|
||||
}
|
||||
|
||||
/** See Grid#measureAllCells */
|
||||
public measureAllCells() {
|
||||
if (this.bottomLeftGrid) {
|
||||
this.bottomLeftGrid.measureAllCells()
|
||||
}
|
||||
if (this.bottomRightGrid) {
|
||||
this.bottomRightGrid.measureAllCells()
|
||||
}
|
||||
if (this.topLeftGrid) {
|
||||
this.topLeftGrid.measureAllCells()
|
||||
}
|
||||
if (this.topRightGrid) {
|
||||
this.topRightGrid.measureAllCells()
|
||||
}
|
||||
}
|
||||
|
||||
public recomputeGridSize({columnIndex = 0, rowIndex = 0} = {}) {
|
||||
|
@ -248,50 +115,20 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
}
|
||||
|
||||
public componentDidMount() {
|
||||
const {scrollLeft, scrollTop} = this.props
|
||||
|
||||
if (scrollLeft > 0 || scrollTop > 0) {
|
||||
const newState: Partial<State> = {}
|
||||
|
||||
if (scrollLeft > 0) {
|
||||
newState.scrollLeft = scrollLeft
|
||||
}
|
||||
|
||||
if (scrollTop > 0) {
|
||||
newState.scrollTop = scrollTop
|
||||
}
|
||||
|
||||
this.setState({...this.state, ...newState})
|
||||
if (this.props.onMount) {
|
||||
this.props.onMount(this)
|
||||
}
|
||||
this.handleInvalidatedGridSize()
|
||||
}
|
||||
|
||||
public componentDidUpdate() {
|
||||
this.handleInvalidatedGridSize()
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {
|
||||
onScroll,
|
||||
scrollLeft: scrollLeftProp, // eslint-disable-line no-unused-vars
|
||||
onSectionRendered,
|
||||
scrollToRow,
|
||||
scrollToColumn,
|
||||
scrollTop: scrollTopProp, // eslint-disable-line no-unused-vars
|
||||
...rest
|
||||
} = this.props
|
||||
const {onScroll, ...rest} = this.props
|
||||
|
||||
this.prepareForRender()
|
||||
|
||||
// Don't render any of our Grids if there are no cells.
|
||||
// This mirrors what Grid does,
|
||||
// And prevents us from recording inaccurage measurements when used with CellMeasurer.
|
||||
if (this.props.width === 0 || this.props.height === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
// scrollTop and scrollLeft props are explicitly filtered out and ignored
|
||||
|
||||
const {scrollLeft, scrollTop} = this.state
|
||||
|
||||
return (
|
||||
|
@ -313,10 +150,7 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
{this.renderBottomRightGrid({
|
||||
...rest,
|
||||
onScroll,
|
||||
onSectionRendered,
|
||||
scrollLeft,
|
||||
scrollToColumn,
|
||||
scrollToRow,
|
||||
scrollTop,
|
||||
})}
|
||||
</div>
|
||||
|
@ -340,20 +174,15 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
} else {
|
||||
return cellRenderer({
|
||||
...rest,
|
||||
style: {
|
||||
...rest.style,
|
||||
},
|
||||
parent: this,
|
||||
rowIndex: rowIndex + fixedRowCount,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private getBottomGridHeight(props: PropsMultiGrid) {
|
||||
const {height} = props
|
||||
|
||||
const topGridHeight = this.getTopGridHeight(props)
|
||||
|
||||
return height - topGridHeight
|
||||
}
|
||||
|
||||
private getLeftGridWidth(props: PropsMultiGrid) {
|
||||
const {fixedColumnCount, columnWidth} = props
|
||||
|
||||
|
@ -376,11 +205,7 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
|
||||
private getRightGridWidth(props: PropsMultiGrid) {
|
||||
const {width} = props
|
||||
|
||||
const leftGridWidth = this.getLeftGridWidth(props)
|
||||
const result = width - leftGridWidth
|
||||
|
||||
return result
|
||||
return width - this.getLeftGridWidth(props)
|
||||
}
|
||||
|
||||
private getTopGridHeight(props: PropsMultiGrid) {
|
||||
|
@ -404,59 +229,72 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
}
|
||||
|
||||
private onScrollbarsScroll = (e: React.MouseEvent<JSX.Element>) => {
|
||||
const {target} = e
|
||||
this.onScroll(target)
|
||||
const {scrollTop} = e.target as HTMLElement
|
||||
const {scrollLeft} = this.state
|
||||
|
||||
this.onScroll({scrollTop, scrollLeft})
|
||||
}
|
||||
|
||||
private onGridScroll = ({scrollLeft}) => {
|
||||
const {scrollTop} = this.state
|
||||
|
||||
this.onScroll({scrollTop, scrollLeft})
|
||||
}
|
||||
|
||||
private onScroll = scrollInfo => {
|
||||
const {scrollLeft, scrollTop} = scrollInfo
|
||||
this.setState({
|
||||
scrollLeft,
|
||||
scrollTop,
|
||||
})
|
||||
|
||||
const {onScroll} = this.props
|
||||
const {scrollLeft, scrollTop} = scrollInfo
|
||||
|
||||
this.setState({scrollLeft, scrollTop})
|
||||
|
||||
if (onScroll) {
|
||||
onScroll(scrollInfo)
|
||||
}
|
||||
}
|
||||
|
||||
private onScrollLeft = scrollInfo => {
|
||||
const {scrollLeft} = scrollInfo
|
||||
this.onScroll({
|
||||
scrollLeft,
|
||||
scrollTop: this.state.scrollTop,
|
||||
})
|
||||
}
|
||||
|
||||
private renderBottomLeftGrid(props) {
|
||||
const {fixedColumnCount, fixedRowCount, rowCount} = props
|
||||
const {fixedColumnCount, fixedRowCount, rowCount, columnWidth} = props
|
||||
|
||||
if (!fixedColumnCount) {
|
||||
return null
|
||||
}
|
||||
|
||||
const width = this.getLeftGridWidth(props)
|
||||
const height = this.getBottomGridHeight(props)
|
||||
const calculatedRowCount = Math.max(rowCount - fixedRowCount, 0)
|
||||
|
||||
return (
|
||||
<Grid
|
||||
{...props}
|
||||
cellRenderer={this.cellRendererBottomLeftGrid}
|
||||
className={this.props.classNameBottomLeftGrid}
|
||||
columnCount={fixedColumnCount}
|
||||
deferredMeasurementCache={this.deferredMeasurementCacheBottomLeftGrid}
|
||||
onScroll={this.onScroll}
|
||||
height={height}
|
||||
ref={this.bottomLeftGridRef}
|
||||
rowCount={Math.max(0, rowCount - fixedRowCount)}
|
||||
rowHeight={this.rowHeightBottomGrid}
|
||||
style={{
|
||||
...this.bottomLeftGridStyle,
|
||||
}}
|
||||
tabIndex={null}
|
||||
width={width}
|
||||
/>
|
||||
<AutoSizer>
|
||||
{({width, height}) => (
|
||||
<FancyScrollbar
|
||||
style={{
|
||||
width,
|
||||
height: this.props.height - ROW_HEIGHT,
|
||||
}}
|
||||
autoHide={true}
|
||||
scrollTop={this.state.scrollTop}
|
||||
scrollLeft={this.state.scrollLeft}
|
||||
setScrollTop={this.onScrollbarsScroll}
|
||||
>
|
||||
<Grid
|
||||
{...props}
|
||||
cellRenderer={this.cellRendererBottomLeftGrid}
|
||||
className={this.props.classNameBottomLeftGrid}
|
||||
columnCount={fixedColumnCount}
|
||||
height={height}
|
||||
ref={this.bottomLeftGridRef}
|
||||
rowCount={calculatedRowCount}
|
||||
rowHeight={ROW_HEIGHT}
|
||||
columnWidth={columnWidth}
|
||||
style={{
|
||||
overflowY: 'hidden',
|
||||
height: calculatedRowCount * ROW_HEIGHT,
|
||||
position: 'absolute',
|
||||
}}
|
||||
tabIndex={null}
|
||||
width={width}
|
||||
/>
|
||||
</FancyScrollbar>
|
||||
)}
|
||||
</AutoSizer>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -466,46 +304,51 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
fixedColumnCount,
|
||||
fixedRowCount,
|
||||
rowCount,
|
||||
scrollToColumn,
|
||||
scrollToRow,
|
||||
scrollLeft,
|
||||
scrollTop,
|
||||
} = props
|
||||
|
||||
const width = this.getRightGridWidth(props)
|
||||
const height = this.getBottomGridHeight(props)
|
||||
const calculatedRowCount = Math.max(0, rowCount - fixedRowCount)
|
||||
|
||||
const leftWidth = this.getLeftGridWidth(props)
|
||||
|
||||
return (
|
||||
<FancyScrollbar
|
||||
style={{...this.bottomRightGridStyle, width, height}}
|
||||
autoHide={true}
|
||||
scrollTop={this.state.scrollTop}
|
||||
scrollLeft={this.state.scrollLeft}
|
||||
setScrollTop={this.onScrollbarsScroll}
|
||||
>
|
||||
<Grid
|
||||
{...props}
|
||||
cellRenderer={this.cellRendererBottomRightGrid}
|
||||
className={this.props.classNameBottomRightGrid}
|
||||
columnCount={Math.max(0, columnCount - fixedColumnCount)}
|
||||
columnWidth={this.columnWidthRightGrid}
|
||||
deferredMeasurementCache={
|
||||
this.deferredMeasurementCacheBottomRightGrid
|
||||
}
|
||||
height={height}
|
||||
ref={this.bottomRightGridRef}
|
||||
rowCount={Math.max(0, rowCount - fixedRowCount)}
|
||||
rowHeight={this.rowHeightBottomGrid}
|
||||
onScroll={this.onScroll}
|
||||
scrollToColumn={scrollToColumn - fixedColumnCount}
|
||||
scrollToRow={scrollToRow - fixedRowCount}
|
||||
style={{
|
||||
...this.bottomRightGridStyle,
|
||||
overflowX: false,
|
||||
overflowY: true,
|
||||
left: 0,
|
||||
}}
|
||||
width={width}
|
||||
/>
|
||||
</FancyScrollbar>
|
||||
<AutoSizer>
|
||||
{({width, height}) => (
|
||||
<FancyScrollbar
|
||||
style={{
|
||||
marginLeft: leftWidth,
|
||||
width: this.props.width - leftWidth,
|
||||
height: this.props.height - ROW_HEIGHT,
|
||||
}}
|
||||
autoHide={true}
|
||||
scrollTop={scrollTop}
|
||||
scrollLeft={scrollLeft}
|
||||
setScrollTop={this.onScrollbarsScroll}
|
||||
>
|
||||
<Grid
|
||||
{..._.omit(props, ['scrollToColumn'])}
|
||||
cellRenderer={this.cellRendererBottomRightGrid}
|
||||
className={this.props.classNameBottomRightGrid}
|
||||
columnCount={Math.max(0, columnCount - fixedColumnCount)}
|
||||
columnWidth={this.columnWidthRightGrid}
|
||||
overscanRowCount={100}
|
||||
height={height}
|
||||
ref={this.bottomRightGridRef}
|
||||
onScroll={this.onGridScroll}
|
||||
rowCount={calculatedRowCount}
|
||||
rowHeight={ROW_HEIGHT}
|
||||
scrollToRow={scrollToRow - fixedRowCount}
|
||||
style={{
|
||||
overflowY: 'hidden',
|
||||
height: calculatedRowCount * ROW_HEIGHT + SCROLLBAR_SIZE_BUFFER,
|
||||
}}
|
||||
width={width - leftWidth}
|
||||
/>
|
||||
</FancyScrollbar>
|
||||
)}
|
||||
</AutoSizer>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -532,13 +375,7 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
}
|
||||
|
||||
private renderTopRightGrid(props) {
|
||||
const {
|
||||
columnCount,
|
||||
enableFixedRowScroll,
|
||||
fixedColumnCount,
|
||||
fixedRowCount,
|
||||
scrollLeft,
|
||||
} = props
|
||||
const {columnCount, fixedColumnCount, fixedRowCount, scrollLeft} = props
|
||||
|
||||
if (!fixedRowCount) {
|
||||
return null
|
||||
|
@ -554,9 +391,8 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
className={this.props.classNameTopRightGrid}
|
||||
columnCount={Math.max(0, columnCount - fixedColumnCount)}
|
||||
columnWidth={this.columnWidthRightGrid}
|
||||
deferredMeasurementCache={this.deferredMeasurementCacheTopRightGrid}
|
||||
height={height}
|
||||
onScroll={enableFixedRowScroll ? this.onScrollLeft : undefined}
|
||||
onScroll={this.onGridScroll}
|
||||
ref={this.topRightGridRef}
|
||||
rowCount={fixedRowCount}
|
||||
scrollLeft={scrollLeft}
|
||||
|
@ -567,23 +403,6 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private rowHeightBottomGrid = ({index}) => {
|
||||
const {fixedRowCount, rowCount, rowHeight} = this.props
|
||||
const {scrollbarSize, showVerticalScrollbar} = this.state
|
||||
|
||||
// An extra cell is added to the count
|
||||
// This gives the smaller Grid extra room for offset,
|
||||
// In case the main (bottom right) Grid has a scrollbar
|
||||
// If no scrollbar, the extra space is overflow:hidden anyway
|
||||
if (showVerticalScrollbar && index === rowCount - fixedRowCount) {
|
||||
return scrollbarSize
|
||||
}
|
||||
|
||||
return typeof rowHeight === 'function'
|
||||
? rowHeight({index: index + fixedRowCount})
|
||||
: rowHeight
|
||||
}
|
||||
|
||||
private topLeftGridRef = ref => {
|
||||
this.topLeftGrid = ref
|
||||
}
|
||||
|
@ -597,43 +416,17 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
* This method recalculates styles only when specific props change.
|
||||
*/
|
||||
private maybeCalculateCachedStyles(resetAll) {
|
||||
const {
|
||||
columnWidth,
|
||||
height,
|
||||
fixedColumnCount,
|
||||
fixedRowCount,
|
||||
rowHeight,
|
||||
style,
|
||||
styleBottomLeftGrid,
|
||||
styleBottomRightGrid,
|
||||
styleTopLeftGrid,
|
||||
styleTopRightGrid,
|
||||
width,
|
||||
} = this.props
|
||||
const {height, width} = this.props
|
||||
|
||||
const sizeChange =
|
||||
resetAll ||
|
||||
height !== this.lastRenderedHeight ||
|
||||
width !== this.lastRenderedWidth
|
||||
const leftSizeChange =
|
||||
resetAll ||
|
||||
columnWidth !== this.lastRenderedColumnWidth ||
|
||||
fixedColumnCount !== this.lastRenderedFixedColumnCount
|
||||
const topSizeChange =
|
||||
resetAll ||
|
||||
fixedRowCount !== this.lastRenderedFixedRowCount ||
|
||||
rowHeight !== this.lastRenderedRowHeight
|
||||
|
||||
if (resetAll || sizeChange || style !== this.lastRenderedStyle) {
|
||||
if (resetAll) {
|
||||
this.containerOuterStyle = {
|
||||
height,
|
||||
overflow: 'visible', // Let :focus outline show through
|
||||
width,
|
||||
...style,
|
||||
}
|
||||
}
|
||||
|
||||
if (resetAll || sizeChange || topSizeChange) {
|
||||
if (resetAll) {
|
||||
this.containerTopStyle = {
|
||||
height: this.getTopGridHeight(this.props),
|
||||
position: 'relative',
|
||||
|
@ -648,68 +441,25 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
}
|
||||
}
|
||||
|
||||
if (
|
||||
resetAll ||
|
||||
styleBottomLeftGrid !== this.lastRenderedStyleBottomLeftGrid
|
||||
) {
|
||||
this.bottomLeftGridStyle = {
|
||||
left: 0,
|
||||
overflowY: 'hidden',
|
||||
overflowX: 'hidden',
|
||||
position: 'absolute',
|
||||
...styleBottomLeftGrid,
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
resetAll ||
|
||||
leftSizeChange ||
|
||||
styleBottomRightGrid !== this.lastRenderedStyleBottomRightGrid
|
||||
) {
|
||||
this.bottomRightGridStyle = {
|
||||
left: this.getLeftGridWidth(this.props),
|
||||
position: 'absolute',
|
||||
...styleBottomRightGrid,
|
||||
}
|
||||
}
|
||||
|
||||
if (resetAll || styleTopLeftGrid !== this.lastRenderedStyleTopLeftGrid) {
|
||||
if (resetAll) {
|
||||
this.topLeftGridStyle = {
|
||||
left: 0,
|
||||
overflowX: 'hidden',
|
||||
overflowY: 'hidden',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
...styleTopLeftGrid,
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
resetAll ||
|
||||
leftSizeChange ||
|
||||
styleTopRightGrid !== this.lastRenderedStyleTopRightGrid
|
||||
) {
|
||||
if (resetAll) {
|
||||
this.topRightGridStyle = {
|
||||
left: this.getLeftGridWidth(this.props),
|
||||
overflowX: 'hidden',
|
||||
overflowY: 'hidden',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
...styleTopRightGrid,
|
||||
}
|
||||
}
|
||||
|
||||
this.lastRenderedColumnWidth = columnWidth
|
||||
this.lastRenderedFixedColumnCount = fixedColumnCount
|
||||
this.lastRenderedFixedRowCount = fixedRowCount
|
||||
this.lastRenderedHeight = height
|
||||
this.lastRenderedRowHeight = rowHeight
|
||||
this.lastRenderedStyle = style
|
||||
this.lastRenderedStyleBottomLeftGrid = styleBottomLeftGrid
|
||||
this.lastRenderedStyleBottomRightGrid = styleBottomRightGrid
|
||||
this.lastRenderedStyleTopLeftGrid = styleTopLeftGrid
|
||||
this.lastRenderedStyleTopRightGrid = styleTopRightGrid
|
||||
this.lastRenderedWidth = width
|
||||
}
|
||||
|
||||
private bottomLeftGridRef = ref => {
|
||||
|
@ -765,48 +515,13 @@ class MultiGrid extends React.PureComponent<PropsMultiGrid, State> {
|
|||
return scrollbarSize
|
||||
}
|
||||
|
||||
return typeof columnWidth === 'function'
|
||||
return _.isFunction(columnWidth)
|
||||
? columnWidth({index: index + fixedColumnCount})
|
||||
: columnWidth
|
||||
}
|
||||
|
||||
private handleInvalidatedGridSize() {
|
||||
if (typeof this.deferredInvalidateColumnIndex === 'number') {
|
||||
const columnIndex = this.deferredInvalidateColumnIndex
|
||||
const rowIndex = this.deferredInvalidateRowIndex
|
||||
|
||||
this.deferredInvalidateColumnIndex = null
|
||||
this.deferredInvalidateRowIndex = null
|
||||
|
||||
this.recomputeGridSize({
|
||||
columnIndex,
|
||||
rowIndex,
|
||||
})
|
||||
this.forceUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
private prepareForRender() {
|
||||
if (
|
||||
this.lastRenderedColumnWidth !== this.props.columnWidth ||
|
||||
this.lastRenderedFixedColumnCount !== this.props.fixedColumnCount
|
||||
) {
|
||||
this.leftGridWidth = null
|
||||
}
|
||||
|
||||
if (
|
||||
this.lastRenderedFixedRowCount !== this.props.fixedRowCount ||
|
||||
this.lastRenderedRowHeight !== this.props.rowHeight
|
||||
) {
|
||||
this.topGridHeight = null
|
||||
}
|
||||
|
||||
this.maybeCalculateCachedStyles(false)
|
||||
|
||||
this.lastRenderedColumnWidth = this.props.columnWidth
|
||||
this.lastRenderedFixedColumnCount = this.props.fixedColumnCount
|
||||
this.lastRenderedFixedRowCount = this.props.fixedRowCount
|
||||
this.lastRenderedRowHeight = this.props.rowHeight
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,14 +2,12 @@ import React, {Component} from 'react'
|
|||
import _ from 'lodash'
|
||||
import classnames from 'classnames'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
import {ColumnSizer, SizedColumnProps} from 'react-virtualized'
|
||||
import {MultiGrid, PropsMultiGrid} from 'src/shared/components/MultiGrid'
|
||||
import {bindActionCreators} from 'redux'
|
||||
import moment from 'moment'
|
||||
|
||||
import {ColumnSizer, SizedColumnProps, AutoSizer} from 'react-virtualized'
|
||||
import {MultiGrid, PropsMultiGrid} from 'src/shared/components/MultiGrid'
|
||||
import {bindActionCreators} from 'redux'
|
||||
import {fastReduce} from 'src/utils/fast'
|
||||
|
||||
import {timeSeriesToTableGraph} from 'src/utils/timeSeriesTransformers'
|
||||
import {
|
||||
computeFieldOptions,
|
||||
|
@ -28,7 +26,6 @@ import {
|
|||
} from 'src/shared/constants/tableGraph'
|
||||
import {generateThresholdsListHexs} from 'src/shared/constants/colorOperations'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import {TimeSeriesServerResponse, TimeSeriesValue} from 'src/types/series'
|
||||
import {ColorString} from 'src/types/colors'
|
||||
import {
|
||||
|
@ -38,6 +35,9 @@ import {
|
|||
Sort,
|
||||
} from 'src/types/dashboards'
|
||||
|
||||
const COLUMN_MIN_WIDTH = 100
|
||||
const ROW_HEIGHT = 30
|
||||
|
||||
interface Label {
|
||||
label: string
|
||||
seriesIndex: number
|
||||
|
@ -49,7 +49,7 @@ interface CellRendererProps {
|
|||
rowIndex: number
|
||||
key: string
|
||||
parent: React.Component<PropsMultiGrid>
|
||||
style: {[x: string]: any}
|
||||
style: React.CSSProperties
|
||||
}
|
||||
|
||||
interface Props {
|
||||
|
@ -77,11 +77,14 @@ interface State {
|
|||
columnWidths: {[x: string]: number}
|
||||
totalColumnWidths: number
|
||||
isTimeVisible: boolean
|
||||
shouldResize: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class TableGraph extends Component<Props, State> {
|
||||
private gridContainer: HTMLDivElement
|
||||
private multiGrid?: MultiGrid
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
|
@ -91,6 +94,7 @@ class TableGraph extends Component<Props, State> {
|
|||
DEFAULT_TIME_FIELD.internalName
|
||||
)
|
||||
this.state = {
|
||||
shouldResize: false,
|
||||
data: [[]],
|
||||
transformedData: [[]],
|
||||
sortedTimeVals: [],
|
||||
|
@ -106,34 +110,13 @@ class TableGraph extends Component<Props, State> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const {
|
||||
hoveredColumnIndex,
|
||||
hoveredRowIndex,
|
||||
timeColumnWidth,
|
||||
sort,
|
||||
transformedData,
|
||||
} = this.state
|
||||
const {transformedData} = this.state
|
||||
|
||||
const {
|
||||
hoverTime,
|
||||
tableOptions,
|
||||
colors,
|
||||
fieldOptions,
|
||||
timeFormat,
|
||||
decimalPlaces,
|
||||
} = this.props
|
||||
const {fixFirstColumn = DEFAULT_FIX_FIRST_COLUMN} = tableOptions
|
||||
const columnCount = _.get(transformedData, ['0', 'length'], 0)
|
||||
const rowCount = columnCount === 0 ? 0 : transformedData.length
|
||||
const COLUMN_MIN_WIDTH = 100
|
||||
const COLUMN_MAX_WIDTH = 1000
|
||||
const ROW_HEIGHT = 30
|
||||
|
||||
const fixedColumnCount = fixFirstColumn && columnCount > 1 ? 1 : undefined
|
||||
|
||||
const tableWidth = _.get(this, ['gridContainer', 'clientWidth'], 0)
|
||||
const tableHeight = _.get(this, ['gridContainer', 'clientHeight'], 0)
|
||||
const fixedColumnCount = this.fixFirstColumn && columnCount > 1 ? 1 : 0
|
||||
const {scrollToColumn, scrollToRow} = this.scrollToColRow
|
||||
|
||||
return (
|
||||
<div
|
||||
className="table-graph-container"
|
||||
|
@ -141,48 +124,64 @@ class TableGraph extends Component<Props, State> {
|
|||
onMouseLeave={this.handleMouseLeave}
|
||||
>
|
||||
{rowCount > 0 && (
|
||||
<ColumnSizer
|
||||
columnCount={columnCount}
|
||||
columnMaxWidth={COLUMN_MAX_WIDTH}
|
||||
columnMinWidth={COLUMN_MIN_WIDTH}
|
||||
width={tableWidth}
|
||||
>
|
||||
{({columnWidth, registerChild}: SizedColumnProps) => (
|
||||
<MultiGrid
|
||||
ref={registerChild}
|
||||
columnCount={columnCount}
|
||||
columnWidth={this.calculateColumnWidth(columnWidth)}
|
||||
rowCount={rowCount}
|
||||
rowHeight={ROW_HEIGHT}
|
||||
height={tableHeight}
|
||||
width={tableWidth}
|
||||
fixedColumnCount={fixedColumnCount}
|
||||
fixedRowCount={1}
|
||||
enableFixedColumnScroll={true}
|
||||
enableFixedRowScroll={true}
|
||||
scrollToRow={scrollToRow}
|
||||
scrollToColumn={scrollToColumn}
|
||||
sort={sort}
|
||||
cellRenderer={this.cellRenderer}
|
||||
hoveredColumnIndex={hoveredColumnIndex}
|
||||
hoveredRowIndex={hoveredRowIndex}
|
||||
hoverTime={hoverTime}
|
||||
colors={colors}
|
||||
fieldOptions={fieldOptions}
|
||||
tableOptions={tableOptions}
|
||||
timeFormat={timeFormat}
|
||||
decimalPlaces={decimalPlaces}
|
||||
timeColumnWidth={timeColumnWidth}
|
||||
classNameBottomRightGrid="table-graph--scroll-window"
|
||||
/>
|
||||
<AutoSizer>
|
||||
{({width, height}) => (
|
||||
<ColumnSizer
|
||||
columnCount={this.computedColumnCount}
|
||||
columnMinWidth={COLUMN_MIN_WIDTH}
|
||||
width={width}
|
||||
>
|
||||
{({
|
||||
adjustedWidth,
|
||||
columnWidth,
|
||||
registerChild,
|
||||
}: SizedColumnProps) => (
|
||||
<MultiGrid
|
||||
onMount={this.handleMultiGridMount}
|
||||
ref={registerChild}
|
||||
columnCount={columnCount}
|
||||
columnWidth={this.calculateColumnWidth(columnWidth)}
|
||||
scrollToRow={scrollToRow}
|
||||
scrollToColumn={scrollToColumn}
|
||||
rowCount={rowCount}
|
||||
rowHeight={ROW_HEIGHT}
|
||||
height={height}
|
||||
width={adjustedWidth}
|
||||
fixedColumnCount={fixedColumnCount}
|
||||
fixedRowCount={1}
|
||||
cellRenderer={this.cellRenderer}
|
||||
classNameBottomRightGrid="table-graph--scroll-window"
|
||||
/>
|
||||
)}
|
||||
</ColumnSizer>
|
||||
)}
|
||||
</ColumnSizer>
|
||||
</AutoSizer>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
public handleMultiGridMount = (ref: MultiGrid) => {
|
||||
this.multiGrid = ref
|
||||
ref.forceUpdate()
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
}
|
||||
|
||||
public get timeField() {
|
||||
const {fieldOptions} = this.props
|
||||
|
||||
return _.find(
|
||||
fieldOptions,
|
||||
f => f.internalName === DEFAULT_TIME_FIELD.internalName
|
||||
)
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
|
||||
const sortField: string = _.get(
|
||||
this.props,
|
||||
['tableOptions', 'sortBy', 'internalName'],
|
||||
|
@ -199,12 +198,10 @@ class TableGraph extends Component<Props, State> {
|
|||
} = this.props
|
||||
const result = timeSeriesToTableGraph(data)
|
||||
const sortedLabels = result.sortedLabels
|
||||
|
||||
const computedFieldOptions = computeFieldOptions(fieldOptions, sortedLabels)
|
||||
|
||||
if (!_.isEqual(computedFieldOptions, fieldOptions)) {
|
||||
this.handleUpdateFieldOptions(computedFieldOptions)
|
||||
}
|
||||
this.handleUpdateFieldOptions(computedFieldOptions)
|
||||
|
||||
const {transformedData, sortedTimeVals, columnWidths} = transformTableData(
|
||||
result.data,
|
||||
sort,
|
||||
|
@ -214,67 +211,65 @@ class TableGraph extends Component<Props, State> {
|
|||
decimalPlaces
|
||||
)
|
||||
|
||||
const timeField = _.find(
|
||||
fieldOptions,
|
||||
f => f.internalName === DEFAULT_TIME_FIELD.internalName
|
||||
)
|
||||
const isTimeVisible = _.get(timeField, 'visible', this.state.isTimeVisible)
|
||||
const isTimeVisible = _.get(this.timeField, 'visible', true)
|
||||
|
||||
this.setState({
|
||||
transformedData,
|
||||
sortedTimeVals,
|
||||
columnWidths: columnWidths.widths,
|
||||
data: result.data,
|
||||
sortedLabels,
|
||||
totalColumnWidths: columnWidths.totalWidths,
|
||||
hoveredColumnIndex: NULL_ARRAY_INDEX,
|
||||
hoveredRowIndex: NULL_ARRAY_INDEX,
|
||||
sort,
|
||||
isTimeVisible,
|
||||
})
|
||||
this.setState(
|
||||
{
|
||||
transformedData,
|
||||
sortedTimeVals,
|
||||
columnWidths: columnWidths.widths,
|
||||
data: result.data,
|
||||
sortedLabels,
|
||||
totalColumnWidths: columnWidths.totalWidths,
|
||||
hoveredColumnIndex: NULL_ARRAY_INDEX,
|
||||
hoveredRowIndex: NULL_ARRAY_INDEX,
|
||||
sort,
|
||||
isTimeVisible,
|
||||
},
|
||||
() => {
|
||||
window.setTimeout(() => {
|
||||
this.forceUpdate()
|
||||
}, 0)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
const updatedProps = _.keys(nextProps).filter(
|
||||
k => !_.isEqual(this.props[k], nextProps[k])
|
||||
)
|
||||
const {tableOptions, fieldOptions, timeFormat, decimalPlaces} = nextProps
|
||||
const {sort} = this.state
|
||||
|
||||
let result = {}
|
||||
|
||||
if (_.includes(updatedProps, 'data')) {
|
||||
if (this.hasDataChanged(nextProps.data)) {
|
||||
result = timeSeriesToTableGraph(nextProps.data)
|
||||
}
|
||||
|
||||
const data = _.get(result, 'data', this.state.data)
|
||||
const sortedLabels = _.get(result, 'sortedLabels', this.state.sortedLabels)
|
||||
|
||||
const computedFieldOptions = computeFieldOptions(fieldOptions, sortedLabels)
|
||||
|
||||
if (_.includes(updatedProps, 'data')) {
|
||||
this.handleUpdateFieldOptions(computedFieldOptions)
|
||||
}
|
||||
|
||||
if (_.isEmpty(data[0])) {
|
||||
return
|
||||
}
|
||||
|
||||
const {sort} = this.state
|
||||
const internalName = _.get(
|
||||
nextProps,
|
||||
['tableOptions', 'sortBy', 'internalName'],
|
||||
''
|
||||
const updatedProps = _.keys(_.omit(nextProps, 'data')).filter(
|
||||
k => !_.isEqual(this.props[k], nextProps[k])
|
||||
)
|
||||
|
||||
const {tableOptions, fieldOptions, timeFormat, decimalPlaces} = nextProps
|
||||
const sortedLabels = _.get(result, 'sortedLabels', this.state.sortedLabels)
|
||||
const computedFieldOptions = computeFieldOptions(fieldOptions, sortedLabels)
|
||||
|
||||
if (this.hasDataChanged(nextProps.data)) {
|
||||
this.handleUpdateFieldOptions(computedFieldOptions)
|
||||
}
|
||||
|
||||
const internalName = _.get(tableOptions, 'sortBy.internalName', '')
|
||||
|
||||
if (
|
||||
!_.get(this.props, ['tableOptions', 'sortBy', 'internalName'], '') ===
|
||||
internalName
|
||||
_.get(this.props, 'tableOptions.sortBy.internalName', '') !== internalName
|
||||
) {
|
||||
sort.direction = DEFAULT_SORT_DIRECTION
|
||||
sort.field = internalName
|
||||
}
|
||||
|
||||
if (
|
||||
_.includes(updatedProps, 'data') ||
|
||||
this.hasDataChanged(nextProps.data) ||
|
||||
_.includes(updatedProps, 'tableOptions') ||
|
||||
_.includes(updatedProps, 'fieldOptions') ||
|
||||
_.includes(updatedProps, 'timeFormat')
|
||||
|
@ -310,33 +305,75 @@ class TableGraph extends Component<Props, State> {
|
|||
columnWidths: columnWidths.widths,
|
||||
totalColumnWidths: columnWidths.totalWidths,
|
||||
isTimeVisible,
|
||||
shouldResize: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private handleUpdateFieldOptions = (fieldOptions: FieldOption[]): void => {
|
||||
const {isInCEO} = this.props
|
||||
if (!isInCEO) {
|
||||
return
|
||||
public componentDidUpdate() {
|
||||
if (this.state.shouldResize) {
|
||||
if (this.multiGrid) {
|
||||
this.multiGrid.recomputeGridSize()
|
||||
}
|
||||
|
||||
this.setState({shouldResize: false})
|
||||
}
|
||||
this.props.handleUpdateFieldOptions(fieldOptions)
|
||||
}
|
||||
|
||||
private hasDataChanged(data): boolean {
|
||||
const newUUID = _.get(data, '0.response.uuid', null)
|
||||
const oldUUID = _.get(this.props.data, '0.response.uuid', null)
|
||||
|
||||
return newUUID !== oldUUID
|
||||
}
|
||||
|
||||
private get fixFirstColumn(): boolean {
|
||||
const {tableOptions} = this.props
|
||||
const {fixFirstColumn = DEFAULT_FIX_FIRST_COLUMN} = tableOptions
|
||||
return fixFirstColumn
|
||||
}
|
||||
|
||||
private get columnCount(): number {
|
||||
const {transformedData} = this.state
|
||||
return _.get(transformedData, ['0', 'length'], 0)
|
||||
}
|
||||
|
||||
private get computedColumnCount(): number {
|
||||
if (this.fixFirstColumn) {
|
||||
return this.columnCount - 1
|
||||
}
|
||||
|
||||
return this.columnCount
|
||||
}
|
||||
|
||||
private get tableWidth(): number {
|
||||
const tableWidth = _.get(this, ['gridContainer', 'clientWidth'], 0)
|
||||
|
||||
return tableWidth
|
||||
}
|
||||
|
||||
private handleUpdateFieldOptions = (fieldOptions: FieldOption[]): void => {
|
||||
const {isInCEO, handleUpdateFieldOptions} = this.props
|
||||
if (isInCEO) {
|
||||
handleUpdateFieldOptions(fieldOptions)
|
||||
}
|
||||
}
|
||||
|
||||
private get isEmpty(): boolean {
|
||||
const {data} = this.state
|
||||
return _.isEmpty(data[0])
|
||||
}
|
||||
|
||||
private get scrollToColRow(): {
|
||||
scrollToRow: number | null
|
||||
scrollToColumn: number | null
|
||||
} {
|
||||
const {data, sortedTimeVals, hoveredColumnIndex, isTimeVisible} = this.state
|
||||
const {hoverTime, tableOptions} = this.props
|
||||
const {sortedTimeVals, hoveredColumnIndex, isTimeVisible} = this.state
|
||||
const {hoverTime} = this.props
|
||||
const hoveringThisTable = hoveredColumnIndex !== NULL_ARRAY_INDEX
|
||||
const notHovering = hoverTime === NULL_HOVER_TIME
|
||||
if (
|
||||
_.isEmpty(data[0]) ||
|
||||
notHovering ||
|
||||
hoveringThisTable ||
|
||||
!isTimeVisible
|
||||
) {
|
||||
return {scrollToColumn: null, scrollToRow: null}
|
||||
if (this.isEmpty || notHovering || hoveringThisTable || !isTimeVisible) {
|
||||
return {scrollToColumn: 0, scrollToRow: -1}
|
||||
}
|
||||
|
||||
const firstDiff = Math.abs(Number(hoverTime) - Number(sortedTimeVals[1])) // sortedTimeVals[0] is "time"
|
||||
|
@ -355,33 +392,35 @@ class TableGraph extends Component<Props, State> {
|
|||
{index: 1, diff: firstDiff}
|
||||
)
|
||||
|
||||
const {verticalTimeAxis} = tableOptions
|
||||
const scrollToColumn = verticalTimeAxis ? null : hoverTimeFound.index
|
||||
const scrollToRow = verticalTimeAxis ? hoverTimeFound.index : null
|
||||
const scrollToColumn = this.isVerticalTimeAxis ? -1 : hoverTimeFound.index
|
||||
const scrollToRow = this.isVerticalTimeAxis ? hoverTimeFound.index : null
|
||||
return {scrollToRow, scrollToColumn}
|
||||
}
|
||||
|
||||
private handleHover = (
|
||||
columnIndex: number,
|
||||
rowIndex: number
|
||||
): (() => void) => (): void => {
|
||||
const {
|
||||
handleSetHoverTime,
|
||||
tableOptions: {verticalTimeAxis},
|
||||
} = this.props
|
||||
private get isVerticalTimeAxis(): boolean {
|
||||
return _.get(
|
||||
this.props,
|
||||
'tableOptions.verticalTimeAxis',
|
||||
DEFAULT_VERTICAL_TIME_AXIS
|
||||
)
|
||||
}
|
||||
|
||||
private handleHover = (e: React.MouseEvent<HTMLElement>) => {
|
||||
const {dataset} = e.target as HTMLElement
|
||||
const {handleSetHoverTime} = this.props
|
||||
const {sortedTimeVals, isTimeVisible} = this.state
|
||||
if (verticalTimeAxis && rowIndex === 0) {
|
||||
if (this.isVerticalTimeAxis && +dataset.rowIndex === 0) {
|
||||
return
|
||||
}
|
||||
if (handleSetHoverTime && isTimeVisible) {
|
||||
const hoverTime = verticalTimeAxis
|
||||
? sortedTimeVals[rowIndex]
|
||||
: sortedTimeVals[columnIndex]
|
||||
handleSetHoverTime(hoverTime.toString())
|
||||
const hoverTime = this.isVerticalTimeAxis
|
||||
? sortedTimeVals[dataset.rowIndex]
|
||||
: sortedTimeVals[dataset.columnIndex]
|
||||
handleSetHoverTime(_.defaultTo(hoverTime, '').toString())
|
||||
}
|
||||
this.setState({
|
||||
hoveredColumnIndex: columnIndex,
|
||||
hoveredRowIndex: rowIndex,
|
||||
hoveredColumnIndex: +dataset.columnIndex,
|
||||
hoveredRowIndex: +dataset.rowIndex,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -426,31 +465,28 @@ class TableGraph extends Component<Props, State> {
|
|||
index: number
|
||||
}): number => {
|
||||
const {index} = column
|
||||
const {
|
||||
tableOptions: {fixFirstColumn},
|
||||
} = this.props
|
||||
|
||||
const {transformedData, columnWidths, totalColumnWidths} = this.state
|
||||
const columnCount = _.get(transformedData, ['0', 'length'], 0)
|
||||
const columnLabel = transformedData[0][index]
|
||||
|
||||
let adjustedColumnSizerWidth = columnWidths[columnLabel]
|
||||
const original = columnWidths[columnLabel]
|
||||
|
||||
const tableWidth = _.get(this, ['gridContainer', 'clientWidth'], 0)
|
||||
if (tableWidth > totalColumnWidths) {
|
||||
if (columnCount === 1) {
|
||||
return columnSizerWidth
|
||||
}
|
||||
const difference = tableWidth - totalColumnWidths
|
||||
const distributeOver =
|
||||
fixFirstColumn && columnCount > 1 ? columnCount - 1 : columnCount
|
||||
const increment = difference / distributeOver
|
||||
adjustedColumnSizerWidth =
|
||||
fixFirstColumn && index === 0
|
||||
? columnWidths[columnLabel]
|
||||
: columnWidths[columnLabel] + increment
|
||||
if (this.fixFirstColumn && index === 0) {
|
||||
return original
|
||||
}
|
||||
|
||||
return adjustedColumnSizerWidth
|
||||
if (this.tableWidth <= totalColumnWidths) {
|
||||
return original
|
||||
}
|
||||
|
||||
if (this.columnCount <= 1) {
|
||||
return columnSizerWidth
|
||||
}
|
||||
|
||||
const difference = this.tableWidth - totalColumnWidths
|
||||
const increment = difference / this.computedColumnCount
|
||||
|
||||
return original + increment
|
||||
}
|
||||
|
||||
private createCellContents = (
|
||||
|
@ -460,16 +496,34 @@ class TableGraph extends Component<Props, State> {
|
|||
isFieldName: boolean
|
||||
): string => {
|
||||
const {timeFormat, decimalPlaces} = this.props
|
||||
|
||||
if (isTimeData) {
|
||||
return `${moment(cellData).format(timeFormat)}`
|
||||
return moment(cellData).format(timeFormat)
|
||||
}
|
||||
if (typeof cellData === 'string' && isFieldName) {
|
||||
return `${fieldName}`
|
||||
if (_.isString(cellData) && isFieldName) {
|
||||
return _.defaultTo(fieldName, '').toString()
|
||||
}
|
||||
if (typeof cellData === 'number' && decimalPlaces.isEnforced) {
|
||||
if (
|
||||
_.isNumber(cellData) &&
|
||||
decimalPlaces.isEnforced &&
|
||||
decimalPlaces.digits < 100
|
||||
) {
|
||||
return cellData.toFixed(decimalPlaces.digits)
|
||||
}
|
||||
return `${cellData}`
|
||||
|
||||
return _.defaultTo(cellData, '').toString()
|
||||
}
|
||||
|
||||
private handleResize = () => {
|
||||
this.forceUpdate()
|
||||
}
|
||||
|
||||
private get timeFieldIndex(): number {
|
||||
const {fieldOptions = [DEFAULT_TIME_FIELD]} = this.props
|
||||
|
||||
return fieldOptions.findIndex(
|
||||
({internalName}) => internalName === DEFAULT_TIME_FIELD.internalName
|
||||
)
|
||||
}
|
||||
|
||||
private cellRenderer = ({
|
||||
|
@ -487,43 +541,24 @@ class TableGraph extends Component<Props, State> {
|
|||
isTimeVisible,
|
||||
} = this.state
|
||||
|
||||
const {
|
||||
fieldOptions = [DEFAULT_TIME_FIELD],
|
||||
tableOptions,
|
||||
colors,
|
||||
} = this.props
|
||||
|
||||
const {
|
||||
verticalTimeAxis = DEFAULT_VERTICAL_TIME_AXIS,
|
||||
fixFirstColumn = DEFAULT_FIX_FIRST_COLUMN,
|
||||
} = tableOptions
|
||||
|
||||
const {fieldOptions = [DEFAULT_TIME_FIELD], colors} = this.props
|
||||
const cellData = transformedData[rowIndex][columnIndex]
|
||||
|
||||
const timeFieldIndex = fieldOptions.findIndex(
|
||||
field => field.internalName === DEFAULT_TIME_FIELD.internalName
|
||||
)
|
||||
|
||||
const isFixedRow = rowIndex === 0 && columnIndex > 0
|
||||
const isFixedColumn = fixFirstColumn && rowIndex > 0 && columnIndex === 0
|
||||
const isSorted = sort.field === cellData
|
||||
const isAscending = sort.direction === ASCENDING
|
||||
const isFirstRow = rowIndex === 0
|
||||
const isFirstCol = columnIndex === 0
|
||||
const isFixedRow = isFirstRow && !isFirstCol
|
||||
const isFixedColumn = this.fixFirstColumn && !isFirstRow && isFirstCol
|
||||
const isTimeData =
|
||||
isTimeVisible &&
|
||||
(verticalTimeAxis
|
||||
? rowIndex !== 0 && columnIndex === timeFieldIndex
|
||||
: rowIndex === timeFieldIndex && columnIndex !== 0)
|
||||
const isFieldName = verticalTimeAxis ? rowIndex === 0 : columnIndex === 0
|
||||
const isFixedCorner = rowIndex === 0 && columnIndex === 0
|
||||
(this.isVerticalTimeAxis
|
||||
? !isFirstRow && columnIndex === this.timeFieldIndex
|
||||
: rowIndex === this.timeFieldIndex && isFirstCol)
|
||||
const isFieldName = this.isVerticalTimeAxis ? isFirstRow : isFirstCol
|
||||
const isFixedCorner = isFirstRow && isFirstCol
|
||||
const isNumerical = _.isNumber(cellData)
|
||||
|
||||
const isHighlightedRow =
|
||||
rowIndex === parent.props.scrollToRow ||
|
||||
(rowIndex === hoveredRowIndex && hoveredRowIndex !== 0)
|
||||
const isHighlightedColumn =
|
||||
columnIndex === parent.props.scrollToColumn ||
|
||||
(columnIndex === hoveredColumnIndex && hoveredColumnIndex !== 0)
|
||||
|
||||
let cellStyle = style
|
||||
|
||||
let cellStyle: React.CSSProperties = style //tslint:disable-line
|
||||
if (
|
||||
!isFixedRow &&
|
||||
!isFixedColumn &&
|
||||
|
@ -531,21 +566,19 @@ class TableGraph extends Component<Props, State> {
|
|||
!isTimeData &&
|
||||
isNumerical
|
||||
) {
|
||||
const {bgColor, textColor} = generateThresholdsListHexs({
|
||||
colors,
|
||||
lastValue: cellData,
|
||||
cellType: 'table',
|
||||
})
|
||||
const thresholdData = {colors, lastValue: cellData, cellType: 'table'}
|
||||
const {bgColor, textColor} = generateThresholdsListHexs(thresholdData)
|
||||
|
||||
cellStyle = {
|
||||
...style,
|
||||
...cellStyle,
|
||||
backgroundColor: bgColor,
|
||||
color: textColor,
|
||||
}
|
||||
}
|
||||
|
||||
const foundField =
|
||||
isFieldName && fieldOptions.find(field => field.internalName === cellData)
|
||||
isFieldName &&
|
||||
fieldOptions.find(({internalName}) => internalName === cellData)
|
||||
const fieldName =
|
||||
foundField && (foundField.displayName || foundField.internalName)
|
||||
|
||||
|
@ -553,14 +586,15 @@ class TableGraph extends Component<Props, State> {
|
|||
'table-graph-cell__fixed-row': isFixedRow,
|
||||
'table-graph-cell__fixed-column': isFixedColumn,
|
||||
'table-graph-cell__fixed-corner': isFixedCorner,
|
||||
'table-graph-cell__highlight-row': isHighlightedRow,
|
||||
'table-graph-cell__highlight-column': isHighlightedColumn,
|
||||
'table-graph-cell__highlight-row':
|
||||
rowIndex === parent.props.scrollToRow ||
|
||||
(rowIndex === hoveredRowIndex && hoveredRowIndex > 0),
|
||||
'table-graph-cell__highlight-column':
|
||||
columnIndex === hoveredColumnIndex && hoveredColumnIndex > 0,
|
||||
'table-graph-cell__numerical': isNumerical,
|
||||
'table-graph-cell__field-name': isFieldName,
|
||||
'table-graph-cell__sort-asc':
|
||||
isFieldName && sort.field === cellData && sort.direction === ASCENDING,
|
||||
'table-graph-cell__sort-desc':
|
||||
isFieldName && sort.field === cellData && sort.direction === DESCENDING,
|
||||
'table-graph-cell__sort-asc': isFieldName && isSorted && isAscending,
|
||||
'table-graph-cell__sort-desc': isFieldName && isSorted && !isAscending,
|
||||
})
|
||||
|
||||
const cellContents = this.createCellContents(
|
||||
|
@ -576,11 +610,13 @@ class TableGraph extends Component<Props, State> {
|
|||
style={cellStyle}
|
||||
className={cellClass}
|
||||
onClick={
|
||||
isFieldName && typeof cellData === 'string'
|
||||
isFieldName && _.isString(cellData)
|
||||
? this.handleClickFieldName(cellData)
|
||||
: null
|
||||
}
|
||||
onMouseOver={_.throttle(this.handleHover(columnIndex, rowIndex), 100)}
|
||||
data-column-index={columnIndex}
|
||||
data-row-index={rowIndex}
|
||||
onMouseOver={this.handleHover}
|
||||
title={cellContents}
|
||||
>
|
||||
{cellContents}
|
||||
|
|
Loading…
Reference in New Issue