diff --git a/ui/src/dashboards/components/GraphOptionsCustomizableColumn.js b/ui/src/dashboards/components/GraphOptionsCustomizableColumn.js
deleted file mode 100644
index e2ad8a95f..000000000
--- a/ui/src/dashboards/components/GraphOptionsCustomizableColumn.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-
-import InputClickToEdit from 'shared/components/InputClickToEdit'
-
-const GraphOptionsCustomizableColumn = ({
- originalColumnName,
- newColumnName,
- onColumnRename,
-}) => {
- return (
-
-
- {originalColumnName}
-
-
-
- )
-}
-const {func, string} = PropTypes
-
-GraphOptionsCustomizableColumn.propTypes = {
- originalColumnName: string,
- newColumnName: string,
- onColumnRename: func,
-}
-
-export default GraphOptionsCustomizableColumn
diff --git a/ui/src/dashboards/components/GraphOptionsCustomizableColumn.tsx b/ui/src/dashboards/components/GraphOptionsCustomizableColumn.tsx
new file mode 100644
index 000000000..cfed2453a
--- /dev/null
+++ b/ui/src/dashboards/components/GraphOptionsCustomizableColumn.tsx
@@ -0,0 +1,48 @@
+import React, {PureComponent} from 'react'
+
+import InputClickToEdit from 'src/shared/components/InputClickToEdit'
+
+type Column = {
+ internalName: string
+ displayName: string
+}
+
+interface Props {
+ internalName: string
+ displayName: string
+ onColumnRename: (column: Column) => void
+}
+
+class GraphOptionsCustomizableColumn extends PureComponent {
+ constructor(props) {
+ super(props)
+
+ this.handleColumnRename = this.handleColumnRename.bind(this)
+ }
+
+ handleColumnRename(rename) {
+ const {onColumnRename, internalName} = this.props
+ onColumnRename({internalName, displayName: rename})
+ }
+
+ render() {
+ const {internalName, displayName} = this.props
+
+ return (
+
+ )
+ }
+}
+
+export default GraphOptionsCustomizableColumn
diff --git a/ui/src/dashboards/components/GraphOptionsCustomizeColumns.js b/ui/src/dashboards/components/GraphOptionsCustomizeColumns.tsx
similarity index 54%
rename from ui/src/dashboards/components/GraphOptionsCustomizeColumns.js
rename to ui/src/dashboards/components/GraphOptionsCustomizeColumns.tsx
index 510f9a06a..3d4e44759 100644
--- a/ui/src/dashboards/components/GraphOptionsCustomizeColumns.js
+++ b/ui/src/dashboards/components/GraphOptionsCustomizeColumns.tsx
@@ -1,10 +1,22 @@
-import React from 'react'
-import PropTypes from 'prop-types'
+import React, {SFC} from 'react'
import GraphOptionsCustomizableColumn from 'src/dashboards/components/GraphOptionsCustomizableColumn'
import uuid from 'uuid'
-const GraphOptionsCustomizeColumns = ({columns, onColumnRename}) => {
+type Column = {
+ internalName: string
+ displayName: string
+}
+
+interface Props {
+ columns: Column[]
+ onColumnRename: (column: Column) => void
+}
+
+const GraphOptionsCustomizeColumns: SFC = ({
+ columns,
+ onColumnRename,
+}) => {
return (
@@ -12,8 +24,8 @@ const GraphOptionsCustomizeColumns = ({columns, onColumnRename}) => {
return (
)
@@ -21,16 +33,5 @@ const GraphOptionsCustomizeColumns = ({columns, onColumnRename}) => {
)
}
-const {arrayOf, func, shape, string} = PropTypes
-
-GraphOptionsCustomizeColumns.propTypes = {
- columns: arrayOf(
- shape({
- name: string,
- newName: string,
- })
- ),
- onColumnRename: func,
-}
export default GraphOptionsCustomizeColumns
diff --git a/ui/src/dashboards/components/TableOptions.tsx b/ui/src/dashboards/components/TableOptions.tsx
index d88770de7..65bf0f56a 100644
--- a/ui/src/dashboards/components/TableOptions.tsx
+++ b/ui/src/dashboards/components/TableOptions.tsx
@@ -18,11 +18,7 @@ import {
updateSingleStatColors,
updateTableOptions,
} from 'src/dashboards/actions/cellEditorOverlay'
-
-const formatColor = color => {
- const {hex, name} = color
- return {hex, name}
-}
+import {TIME_COLUMN_DEFAULT} from 'src/shared/constants/tableGraph'
type Color = {
type: string
@@ -47,10 +43,12 @@ type Options = {
type QueryConfig = {
measurement: string
- fields: [{
- alias: string
- value: string
- }]
+ fields: [
+ {
+ alias: string
+ value: string
+ }
+ ]
}
interface Props {
@@ -63,7 +61,42 @@ interface Props {
tableOptions: Options
}
+const formatColor = color => {
+ const {hex, name} = color
+ return {hex, name}
+}
+
export class TableOptions extends PureComponent {
+ constructor(props) {
+ super(props)
+ }
+
+ componentWillMount() {
+ const {queryConfigs, handleUpdateTableOptions, tableOptions} = this.props
+ const {columnNames} = tableOptions
+ const timeColumn =
+ (columnNames && columnNames.find(c => c.internalName === 'time')) ||
+ TIME_COLUMN_DEFAULT
+
+ const columns = [
+ timeColumn,
+ ..._.flatten(
+ queryConfigs.map(qc => {
+ const {measurement, fields} = qc
+ return fields.map(f => {
+ const internalName = `${measurement}.${f.alias}`
+ const existing = columnNames.find(
+ c => c.internalName === internalName
+ )
+ return existing || {internalName, displayName: ''}
+ })
+ })
+ ),
+ ]
+
+ handleUpdateTableOptions({...tableOptions, columnNames: columns})
+ }
+
handleToggleSingleStatType = () => {}
handleAddThreshold = () => {}
@@ -83,7 +116,14 @@ export class TableOptions extends PureComponent {
handleToggleTextWrapping = () => {}
- handleColumnRename = () => {}
+ handleColumnRename = column => {
+ const {handleUpdateTableOptions, tableOptions} = this.props
+ const {columnNames} = tableOptions
+ const updatedColumns = columnNames.map(
+ op => (op.internalName === column.internalName ? column : op)
+ )
+ handleUpdateTableOptions({...tableOptions, columnNames: updatedColumns})
+ }
handleUpdateColorValue = () => {}
@@ -93,22 +133,13 @@ export class TableOptions extends PureComponent {
const {
singleStatColors,
singleStatType,
- tableOptions: {timeFormat},
+ tableOptions: {timeFormat, columnNames: columns},
} = this.props
const disableAddThreshold = singleStatColors.length > MAX_THRESHOLDS
const TimeAxis = 'vertical'
const sortedColors = _.sortBy(singleStatColors, color => color.value)
- const columns = [
- 'cpu.mean_usage_system',
- 'cpu.mean_usage_idle',
- 'cpu.mean_usage_user',
- ].map(col => ({
- text: col,
- name: col,
- newName: '',
- }))
const tableSortByOptions = [
'cpu.mean_usage_system',
'cpu.mean_usage_idle',
diff --git a/ui/src/shared/components/TableGraph.js b/ui/src/shared/components/TableGraph.js
index d3a400b4c..ed31ed787 100644
--- a/ui/src/shared/components/TableGraph.js
+++ b/ui/src/shared/components/TableGraph.js
@@ -9,6 +9,7 @@ import {
NULL_ROW_INDEX,
NULL_HOVER_TIME,
TIME_FORMAT_DEFAULT,
+ TIME_COLUMN_DEFAULT,
} from 'src/shared/constants/tableGraph'
import {MultiGrid} from 'react-virtualized'
@@ -71,6 +72,9 @@ class TableGraph extends Component {
const timeFormat = tableOptions
? tableOptions.timeFormat
: TIME_FORMAT_DEFAULT
+ const columnNames = tableOptions
+ ? tableOptions.columnNames
+ : [TIME_COLUMN_DEFAULT]
const isFixedRow = rowIndex === 0 && columnIndex > 0
const isFixedColumn = rowIndex > 0 && columnIndex === 0
@@ -94,6 +98,13 @@ class TableGraph extends Component {
'table-graph-cell__numerical': dataIsNumerical,
})
+ const cellData = data[rowIndex][columnIndex]
+ const foundColumn = columnNames.find(
+ column => column.internalName === cellData
+ )
+ const columnName =
+ foundColumn && (foundColumn.displayName || foundColumn.internalName)
+
return (
{isTimeData
- ? `${moment(data[rowIndex][columnIndex]).format(timeFormat)}`
- : `${data[rowIndex][columnIndex]}`}
+ ? `${moment(cellData).format(timeFormat)}`
+ : columnName || `${cellData}`}
)
}
@@ -141,6 +152,9 @@ class TableGraph extends Component {
timeFormat={
tableOptions ? tableOptions.timeFormat : TIME_FORMAT_DEFAULT
}
+ columnNames={
+ tableOptions ? tableOptions.columnNames : [TIME_COLUMN_DEFAULT]
+ }
scrollToRow={hoverTimeRow}
cellRenderer={this.cellRenderer}
hoveredColumnIndex={hoveredColumnIndex}
diff --git a/ui/src/shared/constants/tableGraph.js b/ui/src/shared/constants/tableGraph.js
index ebf97a769..9c87cc65e 100644
--- a/ui/src/shared/constants/tableGraph.js
+++ b/ui/src/shared/constants/tableGraph.js
@@ -6,6 +6,8 @@ export const NULL_HOVER_TIME = '0'
export const TIME_FORMAT_DEFAULT = 'MM/DD/YYYY HH:mm:ss.ss'
export const TIME_FORMAT_CUSTOM = 'Custom'
+export const TIME_COLUMN_DEFAULT = {internalName: 'time', displayName: ''}
+
export const FORMAT_OPTIONS = [
{text: TIME_FORMAT_DEFAULT},
{text: 'MM/DD/YYYY HH:mm'},
@@ -21,9 +23,9 @@ export const FORMAT_OPTIONS = [
export const DEFAULT_TABLE_OPTIONS = {
timeFormat: 'MM/DD/YYYY HH:mm:ss.ss',
verticalTimeAxis: true,
- sortBy: {internalName: 'time', displayName: ''},
+ sortBy: TIME_COLUMN_DEFAULT,
wrapping: 'truncate',
- columnNames: [{internalName: 'time', displayName: ''}],
+ columnNames: [TIME_COLUMN_DEFAULT],
}
export const initializeOptions = cellType => {
diff --git a/ui/test/dashboards/components/GraphOptionsCustomizableColumn.test.tsx b/ui/test/dashboards/components/GraphOptionsCustomizableColumn.test.tsx
new file mode 100644
index 000000000..477807e29
--- /dev/null
+++ b/ui/test/dashboards/components/GraphOptionsCustomizableColumn.test.tsx
@@ -0,0 +1,62 @@
+import React from 'react'
+
+import GraphOptionsCustomizableColumn from 'src/dashboards/components/GraphOptionsCustomizableColumn'
+import InputClickToEdit from 'src/shared/components/InputClickToEdit'
+
+import {shallow} from 'enzyme'
+
+const setup = (override = {}) => {
+ const props = {
+ internalName: '',
+ displayName: '',
+ onColumnRename: () => {},
+ ...override,
+ }
+
+ const wrapper = shallow()
+ const instance = wrapper.instance() as GraphOptionsCustomizableColumn
+
+ return {wrapper, props, instance}
+}
+
+describe('Dashboards.Components.GraphOptionsCustomizableColumn', () => {
+ describe('rendering', () => {
+ it('displays both label div and InputClickToEdit', () => {
+ const {wrapper} = setup()
+ const label = wrapper.find('div').last()
+ const input = wrapper.find(InputClickToEdit)
+
+ expect(label.exists()).toBe(true)
+ expect(input.exists()).toBe(true)
+ })
+
+ describe('when there is an internalName', () => {
+ it('displays the value', () => {
+ const internalName = 'test'
+ const {wrapper} = setup({internalName})
+ const label = wrapper.find('div').last()
+ expect(label.exists()).toBe(true)
+ expect(label.children().contains(internalName)).toBe(true)
+ })
+ })
+ })
+
+ describe('instance methods', () => {
+ describe('#handleColumnRename', () => {
+ it('calls onColumnRename once', () => {
+ const onColumnRename = jest.fn()
+ const internalName = 'test'
+ const {instance} = setup({onColumnRename, internalName})
+ const rename = 'TEST'
+
+ instance.handleColumnRename(rename)
+
+ expect(onColumnRename).toHaveBeenCalledTimes(1)
+ expect(onColumnRename).toHaveBeenCalledWith({
+ internalName,
+ displayName: rename,
+ })
+ })
+ })
+ })
+})
diff --git a/ui/test/dashboards/components/GraphOptionsCustomizeColumns.test.tsx b/ui/test/dashboards/components/GraphOptionsCustomizeColumns.test.tsx
new file mode 100644
index 000000000..23dee525e
--- /dev/null
+++ b/ui/test/dashboards/components/GraphOptionsCustomizeColumns.test.tsx
@@ -0,0 +1,34 @@
+import React from 'react'
+
+import GraphOptionsCustomizeColumns from 'src/dashboards/components/GraphOptionsCustomizeColumns'
+import GraphOptionsCustomizableColumn from 'src/dashboards/components/GraphOptionsCustomizableColumn'
+import {TIME_COLUMN_DEFAULT} from 'src/shared/constants/tableGraph'
+
+import {shallow} from 'enzyme'
+
+const setup = (override = {}) => {
+ const props = {
+ columns: [],
+ onColumnRename: () => {},
+ ...override,
+ }
+
+ const wrapper = shallow()
+
+ return {wrapper, props}
+}
+
+describe('Dashboards.Components.GraphOptionsCustomizeColumns', () => {
+ describe('rendering', () => {
+ it('displays label and all columns passed in', () => {
+ const columns = [TIME_COLUMN_DEFAULT]
+ const {wrapper} = setup({columns})
+ const label = wrapper.find('label')
+ const customizableColumns = wrapper.find(GraphOptionsCustomizableColumn)
+
+ expect(label.exists()).toBe(true)
+ expect(customizableColumns.exists()).toBe(true)
+ expect(customizableColumns.length).toBe(columns.length)
+ })
+ })
+})