diff --git a/ui/src/dashboards/components/GraphOptionsSortBy.js b/ui/src/dashboards/components/GraphOptionsSortBy.js deleted file mode 100644 index d58a2adfb..000000000 --- a/ui/src/dashboards/components/GraphOptionsSortBy.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import Dropdown from 'shared/components/Dropdown' - -const GraphOptionsSortBy = ({sortByOptions, onChooseSortBy}) => -
- - -
- -const {arrayOf, func, shape, string} = PropTypes - -GraphOptionsSortBy.propTypes = { - sortByOptions: arrayOf( - shape({ - text: string.isRequired, - }).isRequired - ), - onChooseSortBy: func, -} - -export default GraphOptionsSortBy diff --git a/ui/src/dashboards/components/GraphOptionsSortBy.tsx b/ui/src/dashboards/components/GraphOptionsSortBy.tsx new file mode 100644 index 000000000..04fffd0c0 --- /dev/null +++ b/ui/src/dashboards/components/GraphOptionsSortBy.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import Dropdown from 'src/shared/components/Dropdown' + +interface TableColumn { + internalName: string + displayName: string +} + +interface Props { + sortByOptions: any[] + onChooseSortBy: (any) => void + selected: TableColumn +} + +const GraphOptionsSortBy = ({sortByOptions, onChooseSortBy, selected} : Props) => { + const selectedValue = selected.displayName || selected.internalName + + return
+ + +
+} + +export default GraphOptionsSortBy diff --git a/ui/src/dashboards/components/TableOptions.tsx b/ui/src/dashboards/components/TableOptions.tsx index f4057cc44..fa9067a16 100644 --- a/ui/src/dashboards/components/TableOptions.tsx +++ b/ui/src/dashboards/components/TableOptions.tsx @@ -30,14 +30,12 @@ type Options = { columnNames: TableColumn[] } -type QueryConfig = { +interface QueryConfig { measurement: string - fields: [ - { - alias: string - value: string - } - ] + fields: { + alias: string + value: string + }[] } interface Props { @@ -52,6 +50,7 @@ export class TableOptions extends PureComponent { super(props) } +<<<<<<< HEAD componentWillMount() { const {queryConfigs, handleUpdateTableOptions, tableOptions} = this.props const {columnNames} = tableOptions @@ -70,11 +69,54 @@ export class TableOptions extends PureComponent { }) ) ] +======= + get columnNames() { + const {tableOptions: {columnNames}} = this.props - handleUpdateTableOptions({...tableOptions, columnNames: columns}) + return columnNames || [] } - handleChooseSortBy = () => {} + get timeColumn() { + return (this.columnNames.find(c => c.internalName === 'time')) || TIME_COLUMN_DEFAULT + } + + get computedColumnNames() { + const {queryConfigs} = this.props + + const queryFields = _.flatten( + queryConfigs.map(({measurement, fields}) => { + return fields.map(({alias}) => { + const internalName = `${measurement}.${alias}` + const existing = this.columnNames.find( + c => c.internalName === internalName + ) + return existing || {internalName, displayName: ''} + }) + })) + + return [this.timeColumn, ...queryFields] + } +>>>>>>> master + + componentWillMount() { + const {handleUpdateTableOptions, tableOptions} = this.props + handleUpdateTableOptions({...tableOptions, columnNames: this.computedColumnNames}) + } + + handleToggleSingleStatType = () => {} + + handleAddThreshold = () => {} + + handleDeleteThreshold = () => () => {} + + handleChooseColor = () => () => {} + + handleChooseSortBy = option => { + const {tableOptions, handleUpdateTableOptions} = this.props + const sortBy = {displayName: option.text, internalName: option.key} + + handleUpdateTableOptions({...tableOptions, sortBy}) + } handleTimeFormatChange = timeFormat => { const {tableOptions, handleUpdateTableOptions} = this.props @@ -96,10 +138,24 @@ export class TableOptions extends PureComponent { } render() { +<<<<<<< HEAD const {tableOptions: {timeFormat, columnNames: columns, verticalTimeAxis}, onResetFocus} = this.props const tableSortByOptions = ['cpu.mean_usage_system', 'cpu.mean_usage_idle', 'cpu.mean_usage_user'].map(col => ({ text: col +======= + const { + tableOptions: {timeFormat, columnNames: columns}, + onResetFocus, + tableOptions, + } = this.props + + const TimeAxis = 'vertical' + + const tableSortByOptions = this.computedColumnNames.map(col => ({ + text: col.displayName || col.internalName, + key: col.internalName, +>>>>>>> master })) return ( @@ -109,8 +165,18 @@ export class TableOptions extends PureComponent {
+ >>>>>> master /> data.length <= 1 - class TableGraph extends Component { constructor(props) { super(props) this.state = { + data: [[]], hoveredColumnIndex: NULL_COLUMN_INDEX, hoveredRowIndex: NULL_ROW_INDEX, + sortByColumnIndex: -1, } } - componentWillMount() { - this._data = [[]] - } - - componentWillUpdate(nextProps) { + componentWillReceiveProps(nextProps) { const {data, unzippedData} = timeSeriesToTableGraph(nextProps.data) - this._data = data - this._unzippedData = unzippedData + const {tableOptions: {sortBy: {internalName}}} = nextProps + const sortByColumnIndex = _.indexOf(data[0], internalName) + + const sortedData = _.sortBy(_.drop(data, 1), sortByColumnIndex) + this.setState({ + data: [data[0], ...sortedData], + unzippedData, + sortByColumnIndex, + }) } calcHoverTimeIndex = (data, hoverTime, verticalTimeAxis) => { @@ -52,9 +56,10 @@ class TableGraph extends Component { handleHover = (columnIndex, rowIndex) => () => { if (this.props.onSetHoverTime) { + const {data} = this.state const hoverTime = this.props.tableOptions.verticalTimeAxis - ? this._data[rowIndex][0] - : this._data[0][columnIndex] + ? data[rowIndex][0] + : data[0][columnIndex] this.props.onSetHoverTime(hoverTime.toString()) this.setState({ hoveredColumnIndex: columnIndex, @@ -75,19 +80,17 @@ class TableGraph extends Component { cellRenderer = ({columnIndex, rowIndex, key, parent, style}) => { const data = _.get(this.props, ['tableOptions', 'verticalTimeAxis'], true) - ? this._data - : this._unzippedData + ? 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 - const timeFormat = tableOptions - ? tableOptions.timeFormat - : TIME_FORMAT_DEFAULT - const columnNames = tableOptions - ? tableOptions.columnNames - : [TIME_COLUMN_DEFAULT] + const timeFormat = _.get(tableOptions, 'timeFormat', TIME_FORMAT_DEFAULT) + const columnNames = _.get(tableOptions, 'columnNames', [ + TIME_COLUMN_DEFAULT, + ]) const isFixedRow = rowIndex === 0 && columnIndex > 0 const isFixedColumn = rowIndex > 0 && columnIndex === 0 @@ -151,14 +154,12 @@ class TableGraph extends Component { } render() { - const {hoveredColumnIndex, hoveredRowIndex} = this.state + const {sortByColumnIndex, hoveredColumnIndex, hoveredRowIndex} = this.state const {hoverTime, tableOptions, colors} = this.props const verticalTimeAxis = _.get(tableOptions, 'verticalTimeAxis', true) - const data = _.get(this.props, ['tableOptions', 'verticalTimeAxis'], true) - ? this._data - : this._unzippedData + const data = verticalTimeAxis ? this.state.data : this.state.unzippedData const columnCount = _.get(data, ['0', 'length'], 0) const rowCount = data.length @@ -166,11 +167,10 @@ class TableGraph extends Component { const ROW_HEIGHT = 30 const tableWidth = this.gridContainer ? this.gridContainer.clientWidth : 0 const tableHeight = this.gridContainer ? this.gridContainer.clientHeight : 0 - const hoverTimeIndex = this.calcHoverTimeIndex( - data, - hoverTime, - verticalTimeAxis - ) + const hoverTimeIndex = + hoveredRowIndex === NULL_ROW_INDEX + ? this.calcHoverTimeIndex(data, hoverTime, verticalTimeAxis) + : hoveredRowIndex return (
{}, + selected: { + internalName: 'boom', + displayName: 'here', + } +} + +const setup = (override = {}) => { + const props = {...defaultProps, ...override} + const wrapper = shallow() + + return {wrapper, props} +} + +describe('Dashboards.Components.GraphOptionsSortBy', () => { + describe('rendering', () => { + it('renders component', () => { + const {wrapper} = setup() + + const dropdown = wrapper.find(Dropdown) + const label = wrapper.find('label') + + expect(dropdown.props()['selected']).toEqual('here') + expect(dropdown.exists()).toBe(true) + expect(label.exists()).toBe(true) + }) + + describe('when selected display name is not available', () => { + it('render internal name as selected', () => { + const {wrapper} = setup({selected: {internalName: 'boom'}}) + + const dropdown = wrapper.find(Dropdown) + + expect(dropdown.props()['selected']).toEqual('boom') + }) + }) + }) +}) diff --git a/ui/test/dashboards/components/TableOptions.test.tsx b/ui/test/dashboards/components/TableOptions.test.tsx index c9242616c..f9d70a91f 100644 --- a/ui/test/dashboards/components/TableOptions.test.tsx +++ b/ui/test/dashboards/components/TableOptions.test.tsx @@ -13,18 +13,51 @@ import ThresholdsListTypeToggle from 'src/shared/components/ThresholdsListTypeTo import {shallow} from 'enzyme' +const queryConfigs = [ + { + measurement: "dev", + fields: [ + { + alias: "boom", + value: "test" + }, + { + alias: "again", + value: "again" + }, + ] + }, + { + measurement: "prod", + fields: [ + { + alias: "boom", + value: "test" + }, + { + alias: "again", + value: "again" + }, + ] + } +] + +const defaultProps = { + queryConfigs: queryConfigs, + handleUpdateTableOptions: () => {}, + tableOptions: { + timeFormat: '', + verticalTimeAxis: true, + sortBy: {internalName: '', displayName: ''}, + wrapping: '', + columnNames: [], + }, + onResetFocus: () => {}, +} + const setup = (override = {}) => { const props = { - queryConfigs: [], - handleUpdateTableOptions: () => {}, - tableOptions: { - timeFormat: '', - verticalTimeAxis: true, - sortBy: {internalName: '', displayName: ''}, - wrapping: '', - columnNames: [], - }, - onResetFocus: () => {}, + ...defaultProps, ...override, } @@ -34,9 +67,65 @@ const setup = (override = {}) => { } describe('Dashboards.Components.TableOptions', () => { + describe('getters', () => { + describe('computedColumnNames', () => { + it('returns the correct column names', () => { + const instance = new TableOptions(defaultProps) + + const expected = [ + { + displayName: '', + internalName: 'time', + }, + { + displayName: '', + internalName: 'dev.boom', + }, + { + displayName: '', + internalName: 'dev.again', + }, + { + displayName: '', + internalName: 'prod.boom', + }, + { + displayName: '', + internalName: 'prod.again', + }, + ] + + expect(instance.computedColumnNames).toEqual(expected) + }) + }) + }) + describe('rendering', () => { it('should render all components', () => { - const {wrapper} = setup() + const queryConfigs = [ + { + measurement: "dev", + fields: [ + { + alias: "boom", + value: "test" + }, + ] + } + ] + + const expectedSortOptions = [ + { + key: 'time', + text: 'time', + }, + { + key: 'dev.boom', + text: 'dev.boom', + }, + ] + + const {wrapper} = setup({ queryConfigs }) const fancyScrollbar = wrapper.find(FancyScrollbar) const graphOptionsTimeFormat = wrapper.find(GraphOptionsTimeFormat) const graphOptionsTimeAxis = wrapper.find(GraphOptionsTimeAxis) @@ -48,6 +137,8 @@ describe('Dashboards.Components.TableOptions', () => { const thresholdsList = wrapper.find(ThresholdsList) const thresholdsListTypeToggle = wrapper.find(ThresholdsListTypeToggle) + expect(graphOptionsSortBy.props().sortByOptions).toEqual(expectedSortOptions) + expect(fancyScrollbar.exists()).toBe(true) expect(graphOptionsTimeFormat.exists()).toBe(true) expect(graphOptionsTimeAxis.exists()).toBe(true)