Merge pull request #3151 from influxdata/table/column-sizing
Table/Adjust Column Sizingpull/10616/head
commit
7a6bd0684c
|
@ -0,0 +1,104 @@
|
||||||
|
import calculateSize from 'calculate-size'
|
||||||
|
import _ from 'lodash'
|
||||||
|
import {reduce} from 'fast.js'
|
||||||
|
|
||||||
|
import {
|
||||||
|
CELL_HORIZONTAL_PADDING,
|
||||||
|
TIME_FIELD_DEFAULT,
|
||||||
|
TIME_FORMAT_DEFAULT,
|
||||||
|
} from 'src/shared/constants/tableGraph'
|
||||||
|
|
||||||
|
const calculateTimeColumnWidth = timeFormat => {
|
||||||
|
// Force usage of longest format names for ideal measurement
|
||||||
|
timeFormat = _.replace(timeFormat, 'MMMM', 'September')
|
||||||
|
timeFormat = _.replace(timeFormat, 'dddd', 'Wednesday')
|
||||||
|
timeFormat = _.replace(timeFormat, 'A', 'AM')
|
||||||
|
timeFormat = _.replace(timeFormat, 'h', '00')
|
||||||
|
timeFormat = _.replace(timeFormat, 'X', '1522286058')
|
||||||
|
|
||||||
|
const {width} = calculateSize(timeFormat, {
|
||||||
|
font: '"RobotoMono", monospace',
|
||||||
|
fontSize: '13px',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
})
|
||||||
|
|
||||||
|
return width + CELL_HORIZONTAL_PADDING
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateMaxWidths = (
|
||||||
|
row,
|
||||||
|
maxColumnWidths,
|
||||||
|
topRow,
|
||||||
|
isTopRow,
|
||||||
|
fieldNames,
|
||||||
|
timeFormatWidth,
|
||||||
|
verticalTimeAxis
|
||||||
|
) => {
|
||||||
|
return reduce(
|
||||||
|
row,
|
||||||
|
(acc, col, c) => {
|
||||||
|
const isLabel =
|
||||||
|
(verticalTimeAxis && isTopRow) || (!verticalTimeAxis && c === 0)
|
||||||
|
|
||||||
|
const foundField = isLabel
|
||||||
|
? fieldNames.find(field => field.internalName === col)
|
||||||
|
: undefined
|
||||||
|
const colValue =
|
||||||
|
foundField && foundField.displayName ? foundField.displayName : `${col}`
|
||||||
|
const columnLabel = topRow[c]
|
||||||
|
|
||||||
|
const useTimeWidth =
|
||||||
|
(columnLabel === TIME_FIELD_DEFAULT.internalName &&
|
||||||
|
verticalTimeAxis &&
|
||||||
|
!isTopRow) ||
|
||||||
|
(!verticalTimeAxis &&
|
||||||
|
isTopRow &&
|
||||||
|
topRow[0] === TIME_FIELD_DEFAULT.internalName &&
|
||||||
|
c !== 0)
|
||||||
|
|
||||||
|
const currentWidth = useTimeWidth
|
||||||
|
? timeFormatWidth
|
||||||
|
: calculateSize(colValue, {
|
||||||
|
font: isLabel ? '"Roboto"' : '"RobotoMono", monospace',
|
||||||
|
fontSize: '13px',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}).width + CELL_HORIZONTAL_PADDING
|
||||||
|
|
||||||
|
const {widths: maxWidths} = maxColumnWidths
|
||||||
|
const maxWidth = _.get(maxWidths, `${columnLabel}`, 0)
|
||||||
|
|
||||||
|
if (isTopRow || currentWidth > maxWidth) {
|
||||||
|
acc.widths[columnLabel] = currentWidth
|
||||||
|
acc.totalWidths += currentWidth - maxWidth
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
},
|
||||||
|
{...maxColumnWidths}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const calculateColumnWidths = (
|
||||||
|
data,
|
||||||
|
fieldNames,
|
||||||
|
timeFormat,
|
||||||
|
verticalTimeAxis
|
||||||
|
) => {
|
||||||
|
const timeFormatWidth = calculateTimeColumnWidth(
|
||||||
|
timeFormat === '' ? TIME_FORMAT_DEFAULT : timeFormat
|
||||||
|
)
|
||||||
|
return reduce(
|
||||||
|
data,
|
||||||
|
(acc, row, r) => {
|
||||||
|
return updateMaxWidths(
|
||||||
|
row,
|
||||||
|
acc,
|
||||||
|
data[0],
|
||||||
|
r === 0,
|
||||||
|
fieldNames,
|
||||||
|
timeFormatWidth,
|
||||||
|
verticalTimeAxis
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{widths: {}, totalWidths: 0}
|
||||||
|
)
|
||||||
|
}
|
|
@ -22,8 +22,6 @@ import {
|
||||||
DEFAULT_SORT,
|
DEFAULT_SORT,
|
||||||
FIX_FIRST_COLUMN_DEFAULT,
|
FIX_FIRST_COLUMN_DEFAULT,
|
||||||
VERTICAL_TIME_AXIS_DEFAULT,
|
VERTICAL_TIME_AXIS_DEFAULT,
|
||||||
calculateTimeColumnWidth,
|
|
||||||
calculateLabelsColumnWidth,
|
|
||||||
} from 'src/shared/constants/tableGraph'
|
} from 'src/shared/constants/tableGraph'
|
||||||
|
|
||||||
import {generateThresholdsListHexs} from 'shared/constants/colorOperations'
|
import {generateThresholdsListHexs} from 'shared/constants/colorOperations'
|
||||||
|
@ -43,12 +41,12 @@ class TableGraph extends Component {
|
||||||
processedData: [[]],
|
processedData: [[]],
|
||||||
sortedTimeVals: [],
|
sortedTimeVals: [],
|
||||||
labels: [],
|
labels: [],
|
||||||
timeColumnWidth: calculateTimeColumnWidth(props.tableOptions.timeFormat),
|
|
||||||
labelsColumnWidth: calculateLabelsColumnWidth(props.data.labels),
|
|
||||||
hoveredColumnIndex: NULL_ARRAY_INDEX,
|
hoveredColumnIndex: NULL_ARRAY_INDEX,
|
||||||
hoveredRowIndex: NULL_ARRAY_INDEX,
|
hoveredRowIndex: NULL_ARRAY_INDEX,
|
||||||
sortField,
|
sortField,
|
||||||
sortDirection: DEFAULT_SORT,
|
sortDirection: DEFAULT_SORT,
|
||||||
|
columnWidths: {},
|
||||||
|
totalColumnWidths: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,13 +67,6 @@ class TableGraph extends Component {
|
||||||
setDataLabels,
|
setDataLabels,
|
||||||
} = nextProps
|
} = nextProps
|
||||||
|
|
||||||
if (timeFormat !== this.props.tableOptions.timeFormat) {
|
|
||||||
this.setState({
|
|
||||||
timeColumnWidth: calculateTimeColumnWidth(timeFormat),
|
|
||||||
})
|
|
||||||
this.multiGridRef.forceUpdateGrids()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setDataLabels) {
|
if (setDataLabels) {
|
||||||
setDataLabels(labels)
|
setDataLabels(labels)
|
||||||
}
|
}
|
||||||
|
@ -92,21 +83,18 @@ class TableGraph extends Component {
|
||||||
sortFieldName = internalName
|
sortFieldName = internalName
|
||||||
}
|
}
|
||||||
|
|
||||||
const {processedData, sortedTimeVals} = processTableData(
|
const {
|
||||||
|
processedData,
|
||||||
|
sortedTimeVals,
|
||||||
|
columnWidths,
|
||||||
|
totalWidths,
|
||||||
|
} = processTableData(
|
||||||
data,
|
data,
|
||||||
sortFieldName,
|
sortFieldName,
|
||||||
direction,
|
direction,
|
||||||
verticalTimeAxis,
|
verticalTimeAxis,
|
||||||
fieldNames
|
fieldNames,
|
||||||
)
|
timeFormat
|
||||||
|
|
||||||
const processedLabels = verticalTimeAxis
|
|
||||||
? processedData[0]
|
|
||||||
: processedData.map(row => row[0])
|
|
||||||
|
|
||||||
const labelsColumnWidth = calculateLabelsColumnWidth(
|
|
||||||
processedLabels,
|
|
||||||
fieldNames
|
|
||||||
)
|
)
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -116,7 +104,8 @@ class TableGraph extends Component {
|
||||||
sortedTimeVals,
|
sortedTimeVals,
|
||||||
sortField: sortFieldName,
|
sortField: sortFieldName,
|
||||||
sortDirection: direction,
|
sortDirection: direction,
|
||||||
labelsColumnWidth,
|
columnWidths,
|
||||||
|
totalColumnWidths: totalWidths,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,31 +194,27 @@ class TableGraph extends Component {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateColumnWidth = columnSizerWidth => column => {
|
calculateColumnWidth = __ => column => {
|
||||||
const {index} = column
|
const {index} = column
|
||||||
const {tableOptions: {verticalTimeAxis}} = this.props
|
const {tableOptions: {fixFirstColumn}} = this.props
|
||||||
const {timeColumnWidth, labelsColumnWidth, processedData} = this.state
|
const {processedData, columnWidths, totalColumnWidths} = this.state
|
||||||
const columnCount = _.get(processedData, ['0', 'length'], 0)
|
const columnCount = _.get(processedData, ['0', 'length'], 0)
|
||||||
const processedLabels = verticalTimeAxis
|
const columnLabel = processedData[0][index]
|
||||||
? processedData[0]
|
|
||||||
: processedData.map(row => row[0])
|
|
||||||
|
|
||||||
const specialColumnWidth = verticalTimeAxis
|
let adjustedColumnSizerWidth = columnWidths[columnLabel]
|
||||||
? timeColumnWidth
|
|
||||||
: labelsColumnWidth
|
|
||||||
|
|
||||||
let adjustedColumnSizerWidth = columnSizerWidth
|
const tableWidth = _.get(this, ['gridContainer', 'clientWidth'], 0)
|
||||||
|
if (tableWidth > totalColumnWidths) {
|
||||||
if (columnSizerWidth !== specialColumnWidth) {
|
const difference = tableWidth - totalColumnWidths
|
||||||
const difference = columnSizerWidth - specialColumnWidth
|
const distributeOver = fixFirstColumn ? columnCount - 1 : columnCount
|
||||||
const increment = difference / (columnCount - 1)
|
const increment = difference / distributeOver
|
||||||
|
adjustedColumnSizerWidth =
|
||||||
adjustedColumnSizerWidth = columnSizerWidth + increment
|
fixFirstColumn && index === 0
|
||||||
|
? columnWidths[columnLabel]
|
||||||
|
: columnWidths[columnLabel] + increment
|
||||||
}
|
}
|
||||||
|
|
||||||
return processedLabels[index] === 'time'
|
return adjustedColumnSizerWidth
|
||||||
? specialColumnWidth
|
|
||||||
: adjustedColumnSizerWidth
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cellRenderer = ({columnIndex, rowIndex, key, parent, style}) => {
|
cellRenderer = ({columnIndex, rowIndex, key, parent, style}) => {
|
||||||
|
@ -307,7 +292,9 @@ class TableGraph extends Component {
|
||||||
})
|
})
|
||||||
|
|
||||||
const cellContents = isTimeData
|
const cellContents = isTimeData
|
||||||
? `${moment(cellData).format(timeFormat)}`
|
? `${moment(cellData).format(
|
||||||
|
timeFormat === '' ? TIME_FORMAT_DEFAULT : timeFormat
|
||||||
|
)}`
|
||||||
: fieldName || `${cellData}`
|
: fieldName || `${cellData}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -334,24 +321,16 @@ class TableGraph extends Component {
|
||||||
hoveredColumnIndex,
|
hoveredColumnIndex,
|
||||||
hoveredRowIndex,
|
hoveredRowIndex,
|
||||||
timeColumnWidth,
|
timeColumnWidth,
|
||||||
labelsColumnWidth,
|
|
||||||
sortField,
|
sortField,
|
||||||
sortDirection,
|
sortDirection,
|
||||||
processedData,
|
processedData,
|
||||||
} = this.state
|
} = this.state
|
||||||
const {
|
const {hoverTime, tableOptions, colors} = this.props
|
||||||
hoverTime,
|
|
||||||
tableOptions,
|
|
||||||
tableOptions: {verticalTimeAxis},
|
|
||||||
colors,
|
|
||||||
} = this.props
|
|
||||||
const {fixFirstColumn = FIX_FIRST_COLUMN_DEFAULT} = tableOptions
|
const {fixFirstColumn = FIX_FIRST_COLUMN_DEFAULT} = tableOptions
|
||||||
const columnCount = _.get(processedData, ['0', 'length'], 0)
|
const columnCount = _.get(processedData, ['0', 'length'], 0)
|
||||||
const rowCount = columnCount === 0 ? 0 : processedData.length
|
const rowCount = columnCount === 0 ? 0 : processedData.length
|
||||||
|
|
||||||
const COLUMN_MIN_WIDTH = verticalTimeAxis
|
const COLUMN_MIN_WIDTH = 100
|
||||||
? labelsColumnWidth
|
|
||||||
: timeColumnWidth
|
|
||||||
const COLUMN_MAX_WIDTH = 1000
|
const COLUMN_MAX_WIDTH = 1000
|
||||||
const ROW_HEIGHT = 30
|
const ROW_HEIGHT = 30
|
||||||
|
|
||||||
|
@ -373,7 +352,6 @@ class TableGraph extends Component {
|
||||||
columnMaxWidth={COLUMN_MAX_WIDTH}
|
columnMaxWidth={COLUMN_MAX_WIDTH}
|
||||||
columnMinWidth={COLUMN_MIN_WIDTH}
|
columnMinWidth={COLUMN_MIN_WIDTH}
|
||||||
width={tableWidth}
|
width={tableWidth}
|
||||||
timeColumnWidth={timeColumnWidth}
|
|
||||||
>
|
>
|
||||||
{({columnWidth, registerChild}) => (
|
{({columnWidth, registerChild}) => (
|
||||||
<MultiGrid
|
<MultiGrid
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
import calculateSize from 'calculate-size'
|
|
||||||
import _ from 'lodash'
|
|
||||||
|
|
||||||
export const NULL_ARRAY_INDEX = -1
|
export const NULL_ARRAY_INDEX = -1
|
||||||
|
|
||||||
export const NULL_HOVER_TIME = '0'
|
export const NULL_HOVER_TIME = '0'
|
||||||
|
@ -21,7 +18,7 @@ export const DEFAULT_SORT = ASCENDING
|
||||||
export const FIX_FIRST_COLUMN_DEFAULT = true
|
export const FIX_FIRST_COLUMN_DEFAULT = true
|
||||||
export const VERTICAL_TIME_AXIS_DEFAULT = true
|
export const VERTICAL_TIME_AXIS_DEFAULT = true
|
||||||
|
|
||||||
export const CELL_HORIZONTAL_PADDING = 18
|
export const CELL_HORIZONTAL_PADDING = 30
|
||||||
|
|
||||||
export const TIME_FORMAT_DEFAULT = 'MM/DD/YYYY HH:mm:ss'
|
export const TIME_FORMAT_DEFAULT = 'MM/DD/YYYY HH:mm:ss'
|
||||||
export const TIME_FORMAT_CUSTOM = 'Custom'
|
export const TIME_FORMAT_CUSTOM = 'Custom'
|
||||||
|
@ -45,52 +42,3 @@ export const DEFAULT_TABLE_OPTIONS = {
|
||||||
fieldNames: [TIME_FIELD_DEFAULT],
|
fieldNames: [TIME_FIELD_DEFAULT],
|
||||||
fixFirstColumn: FIX_FIRST_COLUMN_DEFAULT,
|
fixFirstColumn: FIX_FIRST_COLUMN_DEFAULT,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const calculateTimeColumnWidth = timeFormat => {
|
|
||||||
// Force usage of longest format names for ideal measurement
|
|
||||||
timeFormat = _.replace(timeFormat, 'MMMM', 'September')
|
|
||||||
timeFormat = _.replace(timeFormat, 'dddd', 'Wednesday')
|
|
||||||
timeFormat = _.replace(timeFormat, 'A', 'AM')
|
|
||||||
timeFormat = _.replace(timeFormat, 'h', '00')
|
|
||||||
timeFormat = _.replace(timeFormat, 'X', '1522286058')
|
|
||||||
|
|
||||||
const {width} = calculateSize(timeFormat, {
|
|
||||||
font: '"RobotoMono", monospace',
|
|
||||||
fontSize: '13px',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
})
|
|
||||||
|
|
||||||
return width + CELL_HORIZONTAL_PADDING
|
|
||||||
}
|
|
||||||
|
|
||||||
export const calculateLabelsColumnWidth = (labels, fieldNames) => {
|
|
||||||
if (!labels) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (fieldNames.length === 1) {
|
|
||||||
const longestLabel = labels.reduce((a, b) => (a.length > b.length ? a : b))
|
|
||||||
const {width} = calculateSize(longestLabel, {
|
|
||||||
font: '"RobotoMono", monospace',
|
|
||||||
fontSize: '13px',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
})
|
|
||||||
|
|
||||||
return width + CELL_HORIZONTAL_PADDING
|
|
||||||
}
|
|
||||||
|
|
||||||
const longestFieldName = fieldNames
|
|
||||||
.map(fieldName => {
|
|
||||||
return fieldName.displayName
|
|
||||||
? fieldName.displayName
|
|
||||||
: fieldName.internalName
|
|
||||||
})
|
|
||||||
.reduce((a, b) => (a.length > b.length ? a : b))
|
|
||||||
|
|
||||||
const {width} = calculateSize(longestFieldName, {
|
|
||||||
font: '"RobotoMono", monospace',
|
|
||||||
fontSize: '13px',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
})
|
|
||||||
|
|
||||||
return width + CELL_HORIZONTAL_PADDING
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import {shiftDate} from 'shared/query/helpers'
|
import {shiftDate} from 'shared/query/helpers'
|
||||||
import {map, reduce, filter, forEach, concat, clone} from 'fast.js'
|
import {map, reduce, filter, forEach, concat, clone} from 'fast.js'
|
||||||
|
import {calculateColumnWidths} from 'src/dashboards/utils/tableGraph'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepts an array of raw influxdb responses and returns a format
|
* Accepts an array of raw influxdb responses and returns a format
|
||||||
|
@ -203,7 +204,8 @@ export const processTableData = (
|
||||||
sortFieldName,
|
sortFieldName,
|
||||||
direction,
|
direction,
|
||||||
verticalTimeAxis,
|
verticalTimeAxis,
|
||||||
fieldNames
|
fieldNames,
|
||||||
|
timeFormat
|
||||||
) => {
|
) => {
|
||||||
const sortIndex = _.indexOf(data[0], sortFieldName)
|
const sortIndex = _.indexOf(data[0], sortFieldName)
|
||||||
const sortedData = [
|
const sortedData = [
|
||||||
|
@ -213,8 +215,14 @@ export const processTableData = (
|
||||||
const sortedTimeVals = map(sortedData, r => r[0])
|
const sortedTimeVals = map(sortedData, r => r[0])
|
||||||
const filteredData = filterTableColumns(sortedData, fieldNames)
|
const filteredData = filterTableColumns(sortedData, fieldNames)
|
||||||
const processedData = verticalTimeAxis ? filteredData : _.unzip(filteredData)
|
const processedData = verticalTimeAxis ? filteredData : _.unzip(filteredData)
|
||||||
|
const {widths: columnWidths, totalWidths} = calculateColumnWidths(
|
||||||
|
processedData,
|
||||||
|
fieldNames,
|
||||||
|
timeFormat,
|
||||||
|
verticalTimeAxis
|
||||||
|
)
|
||||||
|
|
||||||
return {processedData, sortedTimeVals}
|
return {processedData, sortedTimeVals, columnWidths, totalWidths}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default timeSeriesToDygraph
|
export default timeSeriesToDygraph
|
||||||
|
|
Loading…
Reference in New Issue