Merge pull request #3010 from influxdata/feature/table-graph-time-axis

Feature/table graph time axis
pull/10616/head
Deniz Kusefoglu 2018-03-19 15:03:04 -07:00 committed by GitHub
commit d179d6f723
8 changed files with 99 additions and 58 deletions

View File

@ -1,29 +1,30 @@
import React from 'react'
import PropTypes from 'prop-types'
const VERTICAL = 'VERTICAL'
const HORIZONTAL = 'HORIZONTAL'
const GraphOptionsTimeAxis = ({TimeAxis, onToggleTimeAxis}) =>
const GraphOptionsTimeAxis = ({verticalTimeAxis, onToggleVerticalTimeAxis}) =>
<div className="form-group col-xs-12 col-sm-6">
<label>Time Axis</label>
<ul className="nav nav-tablist nav-tablist-sm">
<li
className={`${TimeAxis === VERTICAL ? 'active' : ''}`}
onClick={onToggleTimeAxis}
className={verticalTimeAxis ? 'active' : ''}
onClick={onToggleVerticalTimeAxis(true)}
>
Vertical
</li>
<li
className={`${TimeAxis === HORIZONTAL ? 'active' : ''}`}
onClick={onToggleTimeAxis}
className={verticalTimeAxis ? '' : 'active'}
onClick={onToggleVerticalTimeAxis(false)}
>
Horizontal
</li>
</ul>
</div>
const {func, string} = PropTypes
const {bool, func} = PropTypes
GraphOptionsTimeAxis.propTypes = {TimeAxis: string, onToggleTimeAxis: func}
GraphOptionsTimeAxis.propTypes = {
verticalTimeAxis: bool,
onToggleVerticalTimeAxis: func,
}
export default GraphOptionsTimeAxis

View File

@ -10,6 +10,7 @@ import GraphOptionsTimeAxis from 'src/dashboards/components/GraphOptionsTimeAxis
import GraphOptionsSortBy from 'src/dashboards/components/GraphOptionsSortBy'
import GraphOptionsTextWrapping from 'src/dashboards/components/GraphOptionsTextWrapping'
import GraphOptionsCustomizeColumns from 'src/dashboards/components/GraphOptionsCustomizeColumns'
import ThresholdsList from 'src/shared/components/ThresholdsList'
import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeToggle'
@ -51,12 +52,14 @@ export class TableOptions extends PureComponent<Props, {}> {
get columnNames() {
const {tableOptions: {columnNames}} = this.props
return columnNames || []
}
get timeColumn() {
return (this.columnNames.find(c => c.internalName === 'time')) || TIME_COLUMN_DEFAULT
return (
this.columnNames.find(c => c.internalName === 'time') ||
TIME_COLUMN_DEFAULT
)
}
get computedColumnNames() {
@ -71,24 +74,20 @@ export class TableOptions extends PureComponent<Props, {}> {
)
return existing || {internalName, displayName: ''}
})
}))
})
)
return [this.timeColumn, ...queryFields]
}
componentWillMount() {
const {handleUpdateTableOptions, tableOptions} = this.props
handleUpdateTableOptions({...tableOptions, columnNames: this.computedColumnNames})
handleUpdateTableOptions({
...tableOptions,
columnNames: this.computedColumnNames
})
}
handleToggleSingleStatType = () => {}
handleAddThreshold = () => {}
handleDeleteThreshold = () => () => {}
handleChooseColor = () => () => {}
handleChooseSortBy = option => {
const {tableOptions, handleUpdateTableOptions} = this.props
const sortBy = {displayName: option.text, internalName: option.key}
@ -101,7 +100,10 @@ export class TableOptions extends PureComponent<Props, {}> {
handleUpdateTableOptions({...tableOptions, timeFormat})
}
handleToggleTimeAxis = () => {}
onToggleVerticalTimeAxis = verticalTimeAxis => () => {
const {tableOptions, handleUpdateTableOptions} = this.props
handleUpdateTableOptions({...tableOptions, verticalTimeAxis})
}
handleToggleTextWrapping = () => {}
@ -116,16 +118,14 @@ export class TableOptions extends PureComponent<Props, {}> {
render() {
const {
tableOptions: {timeFormat, columnNames: columns},
tableOptions: {timeFormat, columnNames: columns, verticalTimeAxis},
onResetFocus,
tableOptions,
tableOptions
} = this.props
const TimeAxis = 'vertical'
const tableSortByOptions = this.computedColumnNames.map(col => ({
text: col.displayName || col.internalName,
key: col.internalName,
key: col.internalName
}))
return (
@ -141,8 +141,8 @@ export class TableOptions extends PureComponent<Props, {}> {
onTimeFormatChange={this.handleTimeFormatChange}
/>
<GraphOptionsTimeAxis
TimeAxis={TimeAxis}
onToggleTimeAxis={this.handleToggleTimeAxis}
verticalTimeAxis={verticalTimeAxis}
onToggleVerticalTimeAxis={this.onToggleVerticalTimeAxis}
/>
<GraphOptionsSortBy
selected={tableOptions.sortBy || TIME_COLUMN_DEFAULT}
@ -169,11 +169,11 @@ export class TableOptions extends PureComponent<Props, {}> {
}
const mapStateToProps = ({cellEditorOverlay: {cell: {tableOptions}}}) => ({
tableOptions,
tableOptions
})
const mapDispatchToProps = dispatch => ({
handleUpdateTableOptions: bindActionCreators(updateTableOptions, dispatch),
handleUpdateTableOptions: bindActionCreators(updateTableOptions, dispatch)
})
export default connect(mapStateToProps, mapDispatchToProps)(TableOptions)

View File

@ -1,3 +1,5 @@
import {DEFAULT_TABLE_OPTIONS} from 'src/shared/constants/tableGraph'
export const EMPTY_DASHBOARD = {
id: 0,
name: '',
@ -20,6 +22,7 @@ export const NEW_DEFAULT_DASHBOARD_CELL = {
name: 'Untitled Cell',
type: 'line',
queries: [],
tableOptions: DEFAULT_TABLE_OPTIONS,
}
export const NEW_DASHBOARD = {

View File

@ -1,3 +1,5 @@
import _ from 'lodash'
import {
THRESHOLD_TYPE_TEXT,
DEFAULT_THRESHOLDS_LIST_COLORS,
@ -28,7 +30,11 @@ export default function cellEditorOverlay(state = initialState, action) {
)
const gaugeColors = validateGaugeColors(colors)
const tableOptions = cell.tableOptions || initializeOptions('table')
const tableOptions = _.get(
cell,
'tableOptions',
initializeOptions('table')
)
return {
...state,

View File

@ -22,6 +22,7 @@ class TableGraph extends Component {
super(props)
this.state = {
data: [[]],
unzippedData: [[]],
hoveredColumnIndex: NULL_COLUMN_INDEX,
hoveredRowIndex: NULL_ROW_INDEX,
sortByColumnIndex: -1,
@ -29,32 +30,45 @@ class TableGraph extends Component {
}
componentWillReceiveProps(nextProps) {
const {data} = timeSeriesToTableGraph(nextProps.data)
const {data, unzippedData} = timeSeriesToTableGraph(nextProps.data)
const {tableOptions: {sortBy: {internalName}}} = nextProps
const sortByColumnIndex = _.indexOf(data[0], internalName)
const sortedData = _.sortBy(_.drop(data, 1), sortByColumnIndex)
this.setState({data: [data[0], ...sortedData], sortByColumnIndex})
this.setState({
data: [data[0], ...sortedData],
unzippedData,
sortByColumnIndex,
})
}
calcHoverTimeRow = (data, hoverTime) =>
!isEmpty(data) && hoverTime !== NULL_HOVER_TIME
? data.findIndex(
calcHoverTimeIndex = (data, hoverTime, verticalTimeAxis) => {
if (isEmpty(data) || hoverTime === NULL_HOVER_TIME) {
return undefined
}
if (verticalTimeAxis) {
return data.findIndex(
row => row[0] && _.isNumber(row[0]) && row[0] >= hoverTime
)
: undefined
}
return data[0].findIndex(d => _.isNumber(d) && d >= hoverTime)
}
handleHover = (columnIndex, rowIndex) => () => {
if (this.props.onSetHoverTime) {
const {onSetHoverTime, tableOptions} = this.props
const {data} = this.state
this.props.onSetHoverTime(data[rowIndex][0].toString())
if (onSetHoverTime) {
const hoverTime = tableOptions.verticalTimeAxis
? data[rowIndex][0]
: data[0][columnIndex]
onSetHoverTime(hoverTime.toString())
}
this.setState({
hoveredColumnIndex: columnIndex,
hoveredRowIndex: rowIndex,
})
}
}
handleMouseOut = () => {
if (this.props.onSetHoverTime) {
@ -66,10 +80,12 @@ class TableGraph extends Component {
}
}
cellRenderer = ({columnIndex, rowIndex, key, style, parent}) => {
const {hoveredColumnIndex, hoveredRowIndex, data} = this.state
cellRenderer = ({columnIndex, rowIndex, key, parent, style}) => {
const data = _.get(this.props, ['tableOptions', 'verticalTimeAxis'], true)
? this.state.data
: this.state.unzippedData
const {hoveredColumnIndex, hoveredRowIndex} = this.state
const {colors} = this.props
const columnCount = _.get(data, ['0', 'length'], 0)
const rowCount = data.length
const {tableOptions} = this.props
@ -80,12 +96,15 @@ class TableGraph extends Component {
const isFixedRow = rowIndex === 0 && columnIndex > 0
const isFixedColumn = rowIndex > 0 && columnIndex === 0
const isTimeData = isFixedColumn
const isTimeData = tableOptions.verticalTimeAxis
? isFixedColumn
: isFixedRow
const isFixedCorner = rowIndex === 0 && columnIndex === 0
const isLastRow = rowIndex === rowCount - 1
const isLastColumn = columnIndex === columnCount - 1
const isHighlighted =
rowIndex === parent.props.scrollToRow ||
columnIndex === parent.props.scrollToColumn ||
(rowIndex === hoveredRowIndex && hoveredRowIndex !== 0) ||
(columnIndex === hoveredColumnIndex && hoveredColumnIndex !== 0)
const dataIsNumerical = _.isNumber(data[rowIndex][columnIndex])
@ -139,16 +158,20 @@ class TableGraph extends Component {
render() {
const {sortByColumnIndex, hoveredColumnIndex, hoveredRowIndex} = this.state
const {hoverTime, tableOptions, colors} = this.props
const {data} = this.state
const verticalTimeAxis = _.get(tableOptions, 'verticalTimeAxis', true)
const data = verticalTimeAxis ? this.state.data : this.state.unzippedData
const columnCount = _.get(data, ['0', 'length'], 0)
const rowCount = data.length
const COLUMN_WIDTH = 300
const ROW_HEIGHT = 30
const tableWidth = this.gridContainer ? this.gridContainer.clientWidth : 0
const tableHeight = this.gridContainer ? this.gridContainer.clientHeight : 0
const hoverTimeRow =
const hoverTimeIndex =
hoveredRowIndex === NULL_ROW_INDEX
? this.calcHoverTimeRow(data, hoverTime)
? this.calcHoverTimeIndex(data, hoverTime, verticalTimeAxis)
: hoveredRowIndex
return (
@ -175,8 +198,10 @@ class TableGraph extends Component {
columnNames={
tableOptions ? tableOptions.columnNames : [TIME_COLUMN_DEFAULT]
}
scrollToRow={verticalTimeAxis ? hoverTimeIndex : undefined}
scrollToColumn={verticalTimeAxis ? undefined : hoverTimeIndex}
verticalTimeAxis={verticalTimeAxis}
sortByColumnIndex={sortByColumnIndex}
scrollToRow={hoverTimeRow}
cellRenderer={this.cellRenderer}
hoveredColumnIndex={hoveredColumnIndex}
hoveredRowIndex={hoveredRowIndex}

View File

@ -21,8 +21,8 @@ export const FORMAT_OPTIONS = [
]
export const DEFAULT_TABLE_OPTIONS = {
timeFormat: 'MM/DD/YYYY HH:mm:ss.ss',
verticalTimeAxis: true,
timeFormat: TIME_FORMAT_DEFAULT,
sortBy: TIME_COLUMN_DEFAULT,
wrapping: 'truncate',
columnNames: [TIME_COLUMN_DEFAULT],

View File

@ -187,3 +187,7 @@ export const validateGaugeColors = colors => {
return formattedColors
}
export const stringifyColorValues = colors => {
return colors.map(color => ({...color, value: `${color.value}`}))
}

View File

@ -177,9 +177,11 @@ export const timeSeriesToTableGraph = raw => {
const labels = ['time', ...map(sortedLabels, ({label}) => label)]
const tableData = map(sortedTimeSeries, ({time, values}) => [time, ...values])
const data = tableData.length ? [labels, ...tableData] : [[]]
const unzippedData = _.unzip(data)
return {
data: tableData.length ? [labels, ...tableData] : [[]],
data,
unzippedData,
}
}