Convert TableGraph to TS

pull/10616/head
ebb-tide 2018-05-09 13:25:11 -07:00
parent eb73b090cd
commit 30164a1e9b
8 changed files with 147 additions and 107 deletions

View File

@ -119,6 +119,8 @@
"webpack-dev-server": "^2.11.1" "webpack-dev-server": "^2.11.1"
}, },
"dependencies": { "dependencies": {
"@types/chroma-js": "^1.3.4",
"@types/react-virtualized": "^9.18.3",
"axios": "^0.13.1", "axios": "^0.13.1",
"bignumber.js": "^4.0.2", "bignumber.js": "^4.0.2",
"calculate-size": "^1.1.1", "calculate-size": "^1.1.1",

View File

@ -4,8 +4,11 @@ import FancyScrollbar from 'src/shared/components/FancyScrollbar'
import {Grid} from 'react-virtualized' import {Grid} from 'react-virtualized'
const SCROLLBAR_SIZE_BUFFER = 20 const SCROLLBAR_SIZE_BUFFER = 20
type HeightWidthFunction = (arg: {index: number}) => {} | number
interface Props { interface Props {
width: number
height: number
columnCount?: number columnCount?: number
classNameBottomLeftGrid?: string classNameBottomLeftGrid?: string
classNameBottomRightGrid?: string classNameBottomRightGrid?: string
@ -23,15 +26,12 @@ interface Props {
scrollTop?: number scrollTop?: number
scrollLeft?: number scrollLeft?: number
rowCount?: number rowCount?: number
rowHeight?: (arg: {index: number}) => {} | number rowHeight?: number | HeightWidthFunction
columnWidth?: (arg: object) => {} | number columnWidth?: number | HeightWidthFunction
onScroll?: (arg: object) => {} onScroll?: (arg: object) => {}
width: number
height: number
scrollToRow?: () => {}
onSectionRendered?: () => {} onSectionRendered?: () => {}
scrollToColumn?: () => {}
cellRenderer?: (arg: object) => JSX.Element cellRenderer?: (arg: object) => JSX.Element
[key: string]: any // MultiGrid can accept any prop, and will rerender if they change
} }
interface State { interface State {
@ -99,10 +99,10 @@ class MultiGrid extends React.PureComponent<Props, State> {
private deferredMeasurementCacheTopRightGrid: CellMeasurerCacheDecorator private deferredMeasurementCacheTopRightGrid: CellMeasurerCacheDecorator
private leftGridWidth: number | null = 0 private leftGridWidth: number | null = 0
private topGridHeight: number | null = 0 private topGridHeight: number | null = 0
private lastRenderedColumnWidth: (arg: object) => {} | number private lastRenderedColumnWidth: number | HeightWidthFunction
private lastRenderedFixedColumnCount: number = 0 private lastRenderedFixedColumnCount: number = 0
private lastRenderedFixedRowCount: number = 0 private lastRenderedFixedRowCount: number = 0
private lastRenderedRowHeight: (arg: {index: number}) => {} | number private lastRenderedRowHeight: number | HeightWidthFunction
private bottomRightGridStyle: object | null private bottomRightGridStyle: object | null
private topRightGridStyle: object | null private topRightGridStyle: object | null
private lastRenderedStyle: object | null private lastRenderedStyle: object | null

View File

@ -1,5 +1,4 @@
import React, {Component} from 'react' import React, {PureComponent} from 'react'
import PropTypes from 'prop-types'
import _ from 'lodash' import _ from 'lodash'
import classnames from 'classnames' import classnames from 'classnames'
import {connect} from 'react-redux' import {connect} from 'react-redux'
@ -26,12 +25,68 @@ import {
DEFAULT_VERTICAL_TIME_AXIS, DEFAULT_VERTICAL_TIME_AXIS,
DEFAULT_SORT_DIRECTION, DEFAULT_SORT_DIRECTION,
} from 'src/shared/constants/tableGraph' } from 'src/shared/constants/tableGraph'
import {generateThresholdsListHexs} from 'shared/constants/colorOperations' import {generateThresholdsListHexs} from 'src/shared/constants/colorOperations'
import {colorsStringSchema} from 'shared/schemas'
import {ErrorHandling} from 'src/shared/decorators/errors' import {ErrorHandling} from 'src/shared/decorators/errors'
import {TimeSeriesServerResponse} from 'src/types/series'
import {ColorString} from 'src/types/colors'
type dbData = string | number | null
interface TableOptions {
verticalTimeAxis: boolean
sortBy: FieldOption
wrapping?: string
fixFirstColumn: boolean
}
interface DecimalPlaces {
isEnforced: boolean
digits: number
}
interface FieldOption {
internalName: string
displayName: string
visible: boolean
}
interface Sort {
field: string
direction: string
}
interface Props {
data: TimeSeriesServerResponse
tableOptions: TableOptions
timeFormat: string
decimalPlaces: DecimalPlaces
fieldOptions: FieldOption[]
hoverTime: string
handleUpdateFieldOptions: (fieldOptions: FieldOption[]) => void
handleSetHoverTime: (hovertime: string) => void
colors: ColorString
isInCEO: boolean
}
interface State {
data: dbData[][]
transformedData: dbData[][]
sortedTimeVals: number[]
sortedLabels: string[]
hoveredColumnIndex: number
hoveredRowIndex: number
timeColumnWidth: number
sort: Sort
columnWidths: {}
totalColumnWidths: number
isTimeVisible: boolean
}
@ErrorHandling @ErrorHandling
class TableGraph extends Component { class TableGraph extends PureComponent<Props, State> {
private multiGridRef: React.RefObject<MultiGrid>
private gridContainer: React.Ref<HTMLDivElement>
constructor(props) { constructor(props) {
super(props) super(props)
@ -40,6 +95,7 @@ class TableGraph extends Component {
['tableOptions', 'sortBy', 'internalName'], ['tableOptions', 'sortBy', 'internalName'],
DEFAULT_TIME_FIELD.internalName DEFAULT_TIME_FIELD.internalName
) )
this.multiGridRef = React.createRef<MultiGrid>()
this.state = { this.state = {
data: [[]], data: [[]],
@ -51,11 +107,11 @@ class TableGraph extends Component {
sort: {field: sortField, direction: DEFAULT_SORT_DIRECTION}, sort: {field: sortField, direction: DEFAULT_SORT_DIRECTION},
columnWidths: {}, columnWidths: {},
totalColumnWidths: 0, totalColumnWidths: 0,
timeColumnWidth: 0,
isTimeVisible: true, isTimeVisible: true,
} }
} }
public componentDidMount() {
componentDidMount() {
const sortField = _.get( const sortField = _.get(
this.props, this.props,
['tableOptions', 'sortBy', 'internalName'], ['tableOptions', 'sortBy', 'internalName'],
@ -112,7 +168,7 @@ class TableGraph extends Component {
}) })
} }
handleUpdateFieldOptions = fieldOptions => { public handleUpdateFieldOptions = fieldOptions => {
const {isInCEO} = this.props const {isInCEO} = this.props
if (!isInCEO) { if (!isInCEO) {
return return
@ -120,7 +176,7 @@ class TableGraph extends Component {
this.props.handleUpdateFieldOptions(fieldOptions) this.props.handleUpdateFieldOptions(fieldOptions)
} }
componentWillReceiveProps(nextProps) { public componentWillReceiveProps(nextProps) {
const updatedProps = _.keys(nextProps).filter( const updatedProps = _.keys(nextProps).filter(
k => !_.isEqual(this.props[k], nextProps[k]) k => !_.isEqual(this.props[k], nextProps[k])
) )
@ -201,7 +257,7 @@ class TableGraph extends Component {
} }
} }
calcScrollToColRow = () => { public calcScrollToColRow = () => {
const {data, sortedTimeVals, hoveredColumnIndex, isTimeVisible} = this.state const {data, sortedTimeVals, hoveredColumnIndex, isTimeVisible} = this.state
const {hoverTime, tableOptions} = this.props const {hoverTime, tableOptions} = this.props
const hoveringThisTable = hoveredColumnIndex !== NULL_ARRAY_INDEX const hoveringThisTable = hoveredColumnIndex !== NULL_ARRAY_INDEX
@ -215,11 +271,11 @@ class TableGraph extends Component {
return {scrollToColumn: undefined, scrollToRow: undefined} return {scrollToColumn: undefined, scrollToRow: undefined}
} }
const firstDiff = Math.abs(hoverTime - sortedTimeVals[1]) // sortedTimeVals[0] is "time" const firstDiff = Math.abs(Number(hoverTime) - sortedTimeVals[1]) // sortedTimeVals[0] is "time"
const hoverTimeFound = reduce( const hoverTimeFound = reduce(
sortedTimeVals, sortedTimeVals,
(acc, currentTime, index) => { (acc, currentTime, index) => {
const thisDiff = Math.abs(hoverTime - currentTime) const thisDiff = Math.abs(Number(hoverTime) - currentTime)
if (thisDiff < acc.diff) { if (thisDiff < acc.diff) {
return {index, diff: thisDiff} return {index, diff: thisDiff}
} }
@ -234,7 +290,7 @@ class TableGraph extends Component {
return {scrollToRow, scrollToColumn} return {scrollToRow, scrollToColumn}
} }
handleHover = (columnIndex, rowIndex) => () => { public handleHover = (columnIndex, rowIndex) => () => {
const { const {
handleSetHoverTime, handleSetHoverTime,
tableOptions: {verticalTimeAxis}, tableOptions: {verticalTimeAxis},
@ -255,7 +311,7 @@ class TableGraph extends Component {
}) })
} }
handleMouseLeave = () => { public handleMouseLeave = () => {
if (this.props.handleSetHoverTime) { if (this.props.handleSetHoverTime) {
this.props.handleSetHoverTime(NULL_HOVER_TIME) this.props.handleSetHoverTime(NULL_HOVER_TIME)
this.setState({ this.setState({
@ -265,7 +321,7 @@ class TableGraph extends Component {
} }
} }
handleClickFieldName = clickedFieldName => () => { public handleClickFieldName = clickedFieldName => () => {
const {tableOptions, fieldOptions, timeFormat, decimalPlaces} = this.props const {tableOptions, fieldOptions, timeFormat, decimalPlaces} = this.props
const {data, sort} = this.state const {data, sort} = this.state
@ -292,7 +348,7 @@ class TableGraph extends Component {
}) })
} }
calculateColumnWidth = columnSizerWidth => column => { public calculateColumnWidth = columnSizerWidth => column => {
const {index} = column const {index} = column
const { const {
tableOptions: {fixFirstColumn}, tableOptions: {fixFirstColumn},
@ -321,7 +377,7 @@ class TableGraph extends Component {
return adjustedColumnSizerWidth return adjustedColumnSizerWidth
} }
createCellContents = ( public createCellContents = (
cellData, cellData,
fieldName, fieldName,
isTimeData, isTimeData,
@ -341,7 +397,7 @@ class TableGraph extends Component {
return `${cellData}` return `${cellData}`
} }
cellRenderer = ({columnIndex, rowIndex, key, parent, style}) => { public cellRenderer = ({columnIndex, rowIndex, key, parent, style}) => {
const { const {
hoveredColumnIndex, hoveredColumnIndex,
hoveredRowIndex, hoveredRowIndex,
@ -448,12 +504,7 @@ class TableGraph extends Component {
) )
} }
getMultiGridRef = (r, registerChild) => { public render() {
this.multiGridRef = r
return registerChild(r)
}
render() {
const { const {
hoveredColumnIndex, hoveredColumnIndex,
hoveredRowIndex, hoveredRowIndex,
@ -484,7 +535,7 @@ class TableGraph extends Component {
return ( return (
<div <div
className="table-graph-container" className="table-graph-container"
ref={gridContainer => (this.gridContainer = gridContainer)} ref={this.gridContainer}
onMouseLeave={this.handleMouseLeave} onMouseLeave={this.handleMouseLeave}
> >
{rowCount > 0 && ( {rowCount > 0 && (
@ -494,9 +545,11 @@ class TableGraph extends Component {
columnMinWidth={COLUMN_MIN_WIDTH} columnMinWidth={COLUMN_MIN_WIDTH}
width={tableWidth} width={tableWidth}
> >
{({columnWidth, registerChild}) => ( {({columnWidth, registerChild}) => {
registerChild(this.multiGridRef)
return (
<MultiGrid <MultiGrid
ref={r => this.getMultiGridRef(r, registerChild)} ref={this.multiGridRef}
columnCount={columnCount} columnCount={columnCount}
columnWidth={this.calculateColumnWidth(columnWidth)} columnWidth={this.calculateColumnWidth(columnWidth)}
rowCount={rowCount} rowCount={rowCount}
@ -509,8 +562,8 @@ class TableGraph extends Component {
enableFixedRowScroll={true} enableFixedRowScroll={true}
scrollToRow={scrollToRow} scrollToRow={scrollToRow}
scrollToColumn={scrollToColumn} scrollToColumn={scrollToColumn}
sort={sort}
cellRenderer={this.cellRenderer} cellRenderer={this.cellRenderer}
sort={sort}
hoveredColumnIndex={hoveredColumnIndex} hoveredColumnIndex={hoveredColumnIndex}
hoveredRowIndex={hoveredRowIndex} hoveredRowIndex={hoveredRowIndex}
hoverTime={hoverTime} hoverTime={hoverTime}
@ -522,45 +575,14 @@ class TableGraph extends Component {
timeColumnWidth={timeColumnWidth} timeColumnWidth={timeColumnWidth}
classNameBottomRightGrid="table-graph--scroll-window" classNameBottomRightGrid="table-graph--scroll-window"
/> />
)} )
}}
</ColumnSizer> </ColumnSizer>
)} )}
</div> </div>
) )
} }
} }
const {arrayOf, bool, number, shape, string, func} = PropTypes
TableGraph.propTypes = {
data: arrayOf(shape()),
tableOptions: shape({
verticalTimeAxis: bool.isRequired,
sortBy: shape({
internalName: string.isRequired,
displayName: string.isRequired,
visible: bool.isRequired,
}).isRequired,
wrapping: string.isRequired,
fixFirstColumn: bool.isRequired,
}),
timeFormat: string.isRequired,
decimalPlaces: shape({
isEnforced: bool.isRequired,
digits: number.isRequired,
}).isRequired,
fieldOptions: arrayOf(
shape({
internalName: string.isRequired,
displayName: string.isRequired,
visible: bool.isRequired,
})
).isRequired,
hoverTime: string,
handleUpdateFieldOptions: func,
handleSetHoverTime: func,
colors: colorsStringSchema,
isInCEO: bool,
}
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
handleUpdateFieldOptions: bindActionCreators(updateFieldOptions, dispatch), handleUpdateFieldOptions: bindActionCreators(updateFieldOptions, dispatch),

View File

@ -5,7 +5,7 @@ import {
THRESHOLD_COLORS, THRESHOLD_COLORS,
THRESHOLD_TYPE_BASE, THRESHOLD_TYPE_BASE,
THRESHOLD_TYPE_TEXT, THRESHOLD_TYPE_TEXT,
} from 'shared/constants/thresholds' } from 'src/shared/constants/thresholds'
import { import {
CELL_TYPE_LINE, CELL_TYPE_LINE,
@ -48,6 +48,8 @@ export const generateThresholdsListHexs = ({
cellType === CELL_TYPE_TABLE ? '#BEC2CC' : THRESHOLD_COLORS[11].hex, cellType === CELL_TYPE_TABLE ? '#BEC2CC' : THRESHOLD_COLORS[11].hex,
} }
const lastValueNumber = Number(lastValue) || 0 const lastValueNumber = Number(lastValue) || 0
let bgColor
let textColor
if (!colors.length) { if (!colors.length) {
return defaultColoring return defaultColoring
@ -85,16 +87,14 @@ export const generateThresholdsListHexs = ({
colors, colors,
lastValueNumber lastValueNumber
) )
const bgColor = null
const textColor = nearestCrossedThreshold.hex
return {bgColor, textColor} return {bgColor: null, textColor: nearestCrossedThreshold.hex}
} }
// When there is only a base color and it's applued to the background // When there is only a base color and it's applued to the background
if (colors.length === 1) { if (colors.length === 1) {
const bgColor = baseColor.hex bgColor = baseColor.hex
const textColor = getLegibleTextColor(bgColor) textColor = getLegibleTextColor(bgColor)
return {bgColor, textColor} return {bgColor, textColor}
} }
@ -106,16 +106,16 @@ export const generateThresholdsListHexs = ({
lastValueNumber lastValueNumber
) )
const bgColor = nearestCrossedThreshold bgColor = nearestCrossedThreshold
? nearestCrossedThreshold.hex ? nearestCrossedThreshold.hex
: baseColor.hex : baseColor.hex
const textColor = getLegibleTextColor(bgColor) textColor = getLegibleTextColor(bgColor)
return {bgColor, textColor} return {bgColor, textColor}
} }
// If all else fails, use safe default // If all else fails, use safe default
const bgColor = null bgColor = null
const textColor = baseColor.hex textColor = baseColor.hex
return {bgColor, textColor} return {bgColor, textColor}
} }

View File

@ -1,7 +1,12 @@
import {map, reduce} from 'fast.js' import {map, reduce} from 'fast.js'
import {groupByTimeSeriesTransform} from 'src/utils/groupByTimeSeriesTransform' import {groupByTimeSeriesTransform} from 'src/utils/groupByTimeSeriesTransform'
export const timeSeriesToDygraph = (raw = [], isInDataExplorer) => { import {TimeSeriesServerResponse} from 'src/types/series'
export const timeSeriesToDygraph = (
raw: TimeSeriesServerResponse,
isInDataExplorer: boolean
) => {
const isTable = false const isTable = false
const {sortedLabels, sortedTimeSeries} = groupByTimeSeriesTransform( const {sortedLabels, sortedTimeSeries} = groupByTimeSeriesTransform(
raw, raw,
@ -31,7 +36,7 @@ export const timeSeriesToDygraph = (raw = [], isInDataExplorer) => {
} }
} }
export const timeSeriesToTableGraph = raw => { export const timeSeriesToTableGraph = (raw: TimeSeriesServerResponse) => {
const isTable = true const isTable = true
const {sortedLabels, sortedTimeSeries} = groupByTimeSeriesTransform( const {sortedLabels, sortedTimeSeries} = groupByTimeSeriesTransform(
raw, raw,

View File

@ -24,6 +24,10 @@
version "0.22.7" version "0.22.7"
resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.7.tgz#4a92eafedfb2b9f4437d3a4410006d81114c66ce" resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.7.tgz#4a92eafedfb2b9f4437d3a4410006d81114c66ce"
"@types/chroma-js@^1.3.4":
version "1.3.4"
resolved "https://registry.yarnpkg.com/@types/chroma-js/-/chroma-js-1.3.4.tgz#ef6d73041992544f492c5baad96468791ec45af5"
"@types/codemirror@^0.0.56": "@types/codemirror@^0.0.56":
version "0.0.56" version "0.0.56"
resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-0.0.56.tgz#1fcf68df0d0a49791d843dadda7d94891ac88669" resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-0.0.56.tgz#1fcf68df0d0a49791d843dadda7d94891ac88669"
@ -61,7 +65,7 @@
version "9.6.6" version "9.6.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.6.tgz#439b91f9caf3983cad2eef1e11f6bedcbf9431d2" resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.6.tgz#439b91f9caf3983cad2eef1e11f6bedcbf9431d2"
"@types/prop-types@^15.5.2": "@types/prop-types@*", "@types/prop-types@^15.5.2":
version "15.5.2" version "15.5.2"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.2.tgz#3c6b8dceb2906cc87fe4358e809f9d20c8d59be1" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.2.tgz#3c6b8dceb2906cc87fe4358e809f9d20c8d59be1"
@ -84,6 +88,13 @@
"@types/history" "^3" "@types/history" "^3"
"@types/react" "*" "@types/react" "*"
"@types/react-virtualized@^9.18.3":
version "9.18.3"
resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.18.3.tgz#777b3c28bd2b972d0a402f2f9d11bacef550be1c"
dependencies:
"@types/prop-types" "*"
"@types/react" "*"
"@types/react@*", "@types/react@^16.0.38": "@types/react@*", "@types/react@^16.0.38":
version "16.3.12" version "16.3.12"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.3.12.tgz#68d9146f3e9797e38ffbf22f7ed1dde91a2cfd2e" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.3.12.tgz#68d9146f3e9797e38ffbf22f7ed1dde91a2cfd2e"